diff --git a/krita/data/templates/animation/.directory b/krita/data/templates/animation/.directory index c551bced07..65a1e5ebdc 100644 --- a/krita/data/templates/animation/.directory +++ b/krita/data/templates/animation/.directory @@ -1,26 +1,27 @@ [Desktop Entry] Name=Animation Templates Name[ar]=قوالب الحركات Name[ca]=Plantilles d'animació Name[ca@valencia]=Plantilles d'animació Name[cs]=Šablony animací: Name[de]=Animations-Vorlagen Name[el]=Πρότυπα εφέ κίνησης Name[en_GB]=Animation Templates Name[es]=Plantillas de animación Name[eu]=Animazio-txantiloiak +Name[fi]=Animaatiopohjat Name[fr]=Modèles pour animation Name[gl]=Modelos de animación Name[is]=Sniðmát fyrir hreyfimyndir Name[it]=Modelli di animazioni Name[nl]=Animatiesjablonen Name[pl]=Szablony animacji Name[pt]=Modelos de Animações Name[pt_BR]=Modelos de animação Name[sv]=Animeringsmallar Name[tr]=Canlandırma Şablonları Name[uk]=Шаблони анімацій Name[x-test]=xxAnimation Templatesxx Name[zh_CN]=动画模板 Name[zh_TW]=動畫範本 X-KDE-DefaultTab=true diff --git a/krita/data/templates/animation/Anim-Jp-EN.desktop b/krita/data/templates/animation/Anim-Jp-EN.desktop index aa69ed4919..eaca1b9ffa 100644 --- a/krita/data/templates/animation/Anim-Jp-EN.desktop +++ b/krita/data/templates/animation/Anim-Jp-EN.desktop @@ -1,31 +1,32 @@ [Desktop Entry] Type=Link URL=.source/Anim-Jp-EN.kra Icon=template_animation Name=Animation-Japanese-En Name[ar]=حركة يابانية (إنجليزي) Name[ca]=Animació-Japonès-EN Name[ca@valencia]=Animació-Japonés-EN Name[de]=Animation-Japanisch-En Name[el]=Εφέ-κίνησης-Ιαπωνικό-En Name[en_GB]=Animation-Japanese-En Name[es]=Animación-Japonés-En Name[et]=Animation-Japanese-En Name[eu]=Animazioa-Japoniarra-En +Name[fi]=Animaatio-japanilainen-EN Name[fr]=Animation japonaise (en) Name[gl]=Animación-xaponesa-en-inglés Name[is]=Hreyfimynd-Japanska-En Name[it]=Animazione-Giapponese-EN Name[ja]=日本式アニメ(英語版) Name[nl]=Animatie-Japans-En Name[pl]=Animacja-Japońska-En Name[pt]=Animação-Japonês-EN Name[pt_BR]=Animation-Japanese-En Name[ru]=Анимация-японская-англ Name[sk]=Animation-Japanese-En Name[sv]=Animering-japanska-en Name[tr]=Canlandırma-Japonca-İngilizce Name[uk]=Японська анімація (англійською) Name[x-test]=xxAnimation-Japanese-Enxx Name[zh_CN]=日式动画 (英文图层名) Name[zh_TW]=動畫-Japanese-En diff --git a/krita/data/templates/animation/Anim-Jp-JP.desktop b/krita/data/templates/animation/Anim-Jp-JP.desktop index 50e6e6920a..4a7ff9bac7 100644 --- a/krita/data/templates/animation/Anim-Jp-JP.desktop +++ b/krita/data/templates/animation/Anim-Jp-JP.desktop @@ -1,31 +1,32 @@ [Desktop Entry] Type=Link URL=.source/Anim-Jp-JP.kra Icon=template_animation Name=Animation-Japanese-JP Name[ar]=حركة يابانية (ياباني) Name[ca]=Animació-Japonès-JP Name[ca@valencia]=Animació-Japonés-JP Name[de]=Animation-Japanisch-JP Name[el]=Εφέ-κίνησης-Ιαπωνικό-JP Name[en_GB]=Animation-Japanese-JP Name[es]=Animación-Japonés-JP Name[et]=Animation-Japanese-JP Name[eu]=Animazioa-Japoniarra-JP +Name[fi]=Animaatio-japanilainen-JP Name[fr]=Animation japonaise (jp) Name[gl]=Animación-xaponesa-en-xaponés Name[is]=Hreyfimynd-Japanska-JP Name[it]=Animazione-Giapponese-JP Name[ja]=日本式アニメ(日本語版) Name[nl]=Animatie-Japans-JP Name[pl]=Animacja-Japońska-JP Name[pt]=Animação-Japonês-JP Name[pt_BR]=Animation-Japanese-JP Name[ru]=Анимация-японская-японск Name[sk]=Animation-Japanese-JP Name[sv]=Animering-japanska-jp Name[tr]=Canlandırma-Japonca-JP Name[uk]=Японська анімація (японською) Name[x-test]=xxAnimation-Japanese-JPxx Name[zh_CN]=日本动画 (日式) Name[zh_TW]=動畫-Japanese-JP diff --git a/krita/data/templates/comics/a4_waffle_grid.desktop b/krita/data/templates/comics/a4_waffle_grid.desktop index 9dea108a7d..eb1caa54f7 100644 --- a/krita/data/templates/comics/a4_waffle_grid.desktop +++ b/krita/data/templates/comics/a4_waffle_grid.desktop @@ -1,69 +1,71 @@ [Desktop Entry] Type=Link URL=.source/a4_waffle_grid.kra Icon=template_comics_empty Name=waffle-iron grid Name[bs]=mreža sječenog željeza Name[ca]=Graella de ferro Name[ca@valencia]=Graella de ferro Name[da]=vaffeljernsgitter Name[de]=Waffeleisengitter Name[el]=waffle-iron κάνναβος Name[en_GB]=waffle-iron grid Name[es]=rejilla de hierro para gofres Name[et]=Vahvlimasina ruudustik Name[eu]=gofreetarako burdinazko sareta +Name[fi]=vohvelirautaruudukko Name[fr]=Grille en métal gaufré Name[gl]=Grade de 3×5 viñetas Name[is]=vöfflujárnshnit Name[it]=Griglia a wafer Name[ja]=格子状コマ Name[kk]=торлы көзді Name[nb]=vaffeljern-rutenett Name[nds]=Wafeliesengadder Name[nl]=wafelijzer-raster Name[pl]=siatka gofrownicy Name[pt]=grelha de ferro para 'waffles' Name[pt_BR]=Grade de ferro vazia Name[ru]=Страница с ячейками Name[sk]=vaflovo-železná mriežka Name[sv]=våffelmönster Name[tr]=waffle-çelik ızgara Name[uk]=сітка з комірками Name[wa]=grile di fier a wåfes Name[x-test]=xxwaffle-iron gridxx Name[zh_CN]=十五宫格 Name[zh_TW]=鬆餅機格線 Comment=300 dpi, A4 waffle-iron grid comic page with ink and color layers Comment[bs]=300 dpi, A4 mreža sječenog željeza stranica stripa s slojevima za tintu i bojemreža sječenog željeza Comment[ca]=300 ppp, pàgina de còmic amb graella de ferro amb capes de tinta i color Comment[ca@valencia]=300 ppp, pàgina de còmic amb graella de ferro amb capes de tinta i color Comment[da]=300 dpi, A4 tegneserieside i vaffeljernsgitter med blæk og farvelag Comment[de]=Comicseite mit Waffeleisengitter-Muster, Tinten- und Farbebenen. Format A4, Auflösung 300 dpi. Comment[el]=300 dpi, σελίδα κόμικ A4 με waffle-iron κάνναβο και στρώματα μελάνης και χρώματος Comment[en_GB]=300 dpi, A4 waffle-iron grid comic page with ink and colour layers Comment[es]=página de cómic con rejilla de hierro para gofres de tamaño A4, a 300 ppp, con tinta y capas de colores Comment[et]=300 DPI A4 vahvlimasina ruudustikuga koomiksilehekülg tindi- ja värvikihiga Comment[eu]=300 dpi, A4 gofreetarako burdinazko saretadun komiki-orri tintadun eta kolore-geruzaduna +Comment[fi]=300 dpi:n A4-kokoinen vohvelirautaruudukko sarjakuvalle muste- ja väritasoin Comment[fr]=Page de bande dessinée avec grille en métal gaufré en A4 300 dpi avec encre et calques de couleurs Comment[gl]=Páxina de banda deseñada de grade en A4 a 300 dpi con 3×5 viñetas regulares e capas de tinta e cor. Comment[is]=300 pát, A4 vöfflujárnshnit teiknimyndasíða með lögum fyrir blek og liti Comment[it]=Pagina di fumetti con griglia a wafer a 300 dpi, A4, con livelli per inchiostro e colore Comment[ja]=300 dpi A4 サイズの、ペン入れレイヤーと彩色レイヤーを備えた格子状コマテンプレート Comment[kk]=300 н/д A4 торлы көзді парақтағы комикс Comment[nb]=300 dpi, A4 tegneserieside med vaffeljern-rutenett, med tusj- og fargelag Comment[nds]=300 dpi, A4 Wafeliesengadder-Comicsiet mit Dint un Klöörlagen. Comment[nl]=300 dpi, A4 wafelijzer-raster strippagina met inkt en kleurlagen Comment[pl]=300 dpi, strona A4 siatki gofrownicy z warstwami tuszu i koloru Comment[pt]=banda desenhada A4, em grelha de 'waffle' a 300 ppp, com camadas de cores e de pinturas Comment[pt_BR]=Página de quadrinhos A4, em grade de ferro a 300 ppp, com camadas de cores e de pinturas Comment[ru]=300 dpi, страница комикса в формате A4 с ячейками и слоями контуров и цветов Comment[sk]=300 dpi, A4 vaflovo železná mriežka komiksovej strany s atramentom a farebnými vrstvami Comment[sv]=300 punkter/tum, A4 våffelmönstrad seriesida med bläck- och färglager Comment[tr]=300 dpi, A4 waffle-çelik ızgara mürekkep ve renk katmanlı çizgi roman sayfası Comment[uk]=300 т/д, сторінка коміксу у форматі A4 з комірками та шарами контурів та кольорів Comment[wa]=Pådje A4 di binde d' imådjes avou on discôpaedje come ene grile di fier a wåfes avou des coûtches d' intche eyet d' coleurs. Comment[x-test]=xx300 dpi, A4 waffle-iron grid comic page with ink and color layersxx Comment[zh_CN]=300 DPI,A4 尺寸的十五宫格网格漫画页,内置线稿和着色图层 Comment[zh_TW]=300 dpi,A4 大小的烘餅鐵模狀的格線,有墨水與顏色圖層 X-Krita-Version=28 diff --git a/krita/data/templates/design/Designcinema16_10_2484x1200_96dpiRGB_8bit_.desktop b/krita/data/templates/design/Designcinema16_10_2484x1200_96dpiRGB_8bit_.desktop index 488cf75118..c522a6eed4 100644 --- a/krita/data/templates/design/Designcinema16_10_2484x1200_96dpiRGB_8bit_.desktop +++ b/krita/data/templates/design/Designcinema16_10_2484x1200_96dpiRGB_8bit_.desktop @@ -1,38 +1,39 @@ [Desktop Entry] Icon=template_ratio_1610 Name=Design cinema 16:10 [ 2484x1200 , 96dpi RGB , 8bit ] Name[ar]=تصميم سينمائي ١٦:١٠ [ ٢٤٨٤×١٢٠٠ ، ٩٦ نقطة/بوصة ، ٨ بتّ ] Name[bs]=Design cinema 16:10 [ 2484x1200 , 96dpi RGB , 8bit ] Name[ca]=Disseny de cine 16:10 [2484x1200, 96 ppp amb RGB, 8 bits] Name[ca@valencia]=Disseny de cine 16:10 [2484x1200, 96 ppp amb RGB, 8 bits] Name[cs]=Návrh kino 16:10 [ 2484x1200 , 96dpi RGB , 8bit ] Name[da]=Design-cinema 16:10 [ 2484x1200 , 96dpi RGB , 8bit ] Name[de]=Design-Kino 16:10 [ 2484x1200 , 96dpi RGB , 8bit ] Name[el]=Design cinema 16:10 [ 2484x1200 , 96dpi RGB , 8bit ] Name[en_GB]=Design cinema 16:10 [ 2484x1200 , 96dpi RGB , 8bit ] Name[es]=Diseño de cine 16:10 [ 2484x1200 , 96dpi RGB , 8bit ] Name[et]=Disainkino 16:10 [ 2484x1200 , 96dpi RGB , 8bit ] Name[eu]=Zinema-diseinua 16:10 [2484 x 1200, 96 dpi GBU, 8 bit] +Name[fi]=Elokuvasuunnitelma 16 : 10 [2484 × 1200, 96 dpi RGB, 8 bit] Name[fr]=style cinéma 16:10 [ 2484x1200, 96dpi RGB, 8bit ] Name[gl]=Deseño de cine 16:10 (2484×1200, 96 dpi RGB, 8 bits) Name[hu]=Tervező mozi 16:10 [ 2484x1200 , 96dpi RGB , 8bit ] Name[is]=Hanna kvikmynd 16:10 [ 2484x1200 , 96pát RGB , 8bita ] Name[it]=Stile cinema 16:10 [ 2484x1200 , 96dpi RGB , 8bit ] Name[ja]=映画 16:10 [ 2484x1200、96dpi RGB、8 ビット ] Name[kk]=Кино пішімі 106:1 [ 2484x1200 , 96 н/д RGB , 8бит ] Name[nb]=Designkino 16:10 [ 2484x1200 , 96dpi RGB , 8bit ] Name[nl]=Design cinema 16:10 [ 2484x1200 , 96dpi RGB , 8bit ] Name[pl]=Kino projekcyjne 16:10 [ 2484x1200 , 96dpi RGB , 8bit ] Name[pt]=Desenho de cinema 16:10 [ 2484x1200 , 96ppp RGB , 8-bits ] Name[pt_BR]=Design de cinema 16:10 [ 2484x1200, 96dpi RGB, 8bits ] Name[ru]=Дизайн кино 16:10 [ 2484x1200 , 96dpi RGB , 8 бит ] Name[sk]=Design cinema 16:10 [ 2484x1200 , 96dpi RGB , 8bit ] Name[sv]=Design film 16:10 [ 2484x1200, 96 punkter/tum RGB, 8 bitar ] Name[tr]=Sineme tasarla 16:10 [ 2484x1200 , 96dpi RGB , 8bit ] Name[uk]=Компонування кіноекрана 16:10 [2484⨯1200, 96 т./д., RGB, 8 бітів] Name[x-test]=xxDesign cinema 16:10 [ 2484x1200 , 96dpi RGB , 8bit ]xx Name[zh_CN]=16:10 电影荧幕设计模板 [ 2484x1200 像素, 96dpi RGB , 8 位 ] Name[zh_TW]=設計電影院 16:10 [ 2484x1200 , 96dpi RGB , 8bit ] Type=Link URL[$e]=.source/Designcinema16_10_2484x1200_96dpiRGB_8bit_.kra X-KDE-Hidden=false diff --git a/krita/data/templates/design/Designcinema2.39_1_2484x1040_96dpiRGB_8bit_.desktop b/krita/data/templates/design/Designcinema2.39_1_2484x1040_96dpiRGB_8bit_.desktop index 42fead5158..6d76d111a6 100644 --- a/krita/data/templates/design/Designcinema2.39_1_2484x1040_96dpiRGB_8bit_.desktop +++ b/krita/data/templates/design/Designcinema2.39_1_2484x1040_96dpiRGB_8bit_.desktop @@ -1,38 +1,39 @@ [Desktop Entry] Icon=template_ratio_2391 Name=Design cinema 2.39:1 [ 2484x1040 , 96dpi RGB , 8bit ] Name[ar]=تصميم سينمائي ٢٫٣٩:١ [ ٢٤٨٤×١٠٤٠ ، ٩٦ نقطة/بوصة ، ٨ بتّ ] Name[bs]=Design cinema 2.39:1 [ 2484x1040 , 96dpi RGB , 8bit ] Name[ca]=Disseny de cine 2,39:1 [2484x1040, 96 ppp amb RGB, 8 bits] Name[ca@valencia]=Disseny de cine 2,39:1 [2484x1040, 96 ppp amb RGB, 8 bits] Name[cs]=Návrh kino 2.39:1 [ 2484x1040 , 96dpi RGB , 8bit ] Name[da]=Design-cinema 2.39:1 [ 2484x1040 , 96dpi RGB , 8bit ] Name[de]=Design-Kino 2.39:1 [ 2484x1040 , 96dpi RGB , 8bit ] Name[el]=Design cinema 2.39:1 [ 2484x1040 , 96dpi RGB , 8bit ] Name[en_GB]=Design cinema 2.39:1 [ 2484x1040 , 96dpi RGB , 8bit ] Name[es]=Diseño de cine 2.39:1 [ 2484x1040 , 96dpi RGB , 8bit ] Name[et]=Disainkino 2,39:1 [ 2484x1040 , 96dpi RGB , 8bit ] Name[eu]=Zinema-diseinua 2.39:1 [2484 x 1040, 96 dpi GBU, 8 bit] +Name[fi]=Elokuvasuunnitelma 2,39 : 1 [2484 × 1040, 96 dpi RGB, 8 bit] Name[fr]=style cinéma 2.39:1 [ 2484x1040, 96dpi RGB, 8bit ] Name[gl]=Deseño de cine 2.39:1 (2484×1040, 96 dpi RGB, 8 bits) Name[hu]=Tervező mozi 2.39:1 [ 2484x1040 , 96dpi RGB , 8bit ] Name[is]=Hanna kvikmynd 2.39:1 [ 2484x1040 , 96pát RGB , 8bita ] Name[it]=Stile cinema 2.39:1 [ 2484x1040 , 96dpi RGB , 8bit ] Name[ja]=映画 2.39:1 [ 2484x1040、96dpi RGB、8 ビット ] Name[kk]=Кино пішімі 2.39:1 [ 2484x1040 , 96 н/д RGB , 8бит ] Name[nb]=Designkino 2.39:1 [ 2484x1040 , 96dpi RGB , 8bit ] Name[nl]=Design cinema 2.39:1 [ 2484x1040 , 96dpi RGB , 8bit ] Name[pl]=Kino projekcyjne 2.39:1 [ 2484x1040 , 96dpi RGB , 8bit ] Name[pt]=Desenho de cinema 2,39:1 [ 2484x1040 , 96ppp RGB , 8-bits ] Name[pt_BR]=Design de cinema 2.39:1 [ 2484x1040, 96dpi RGB, 8bits ] Name[ru]=Дизайн кино 2.39:1 [ 2484x1040 , 96dpi RGB , 8 бит ] Name[sk]=Design cinema 2.39:1 [ 2484x1040 , 96dpi RGB , 8bit ] Name[sv]=Design film 2,39:1 [ 2484x1040, 96 punkter/tum RGB, 8 bitar ] Name[tr]=Sineme tasarla 2.39:1 [ 2484x1040 , 96dpi RGB , 8bit ] Name[uk]=Компонування кіноекрана 2,39:1 [2484⨯1040, 96 т./д., RGB, 8 бітів] Name[x-test]=xxDesign cinema 2.39:1 [ 2484x1040 , 96dpi RGB , 8bit ]xx Name[zh_CN]=2.39:1 电影荧幕设计模板 [ 2484x1040 像素, 96dpi RGB , 8 位] Name[zh_TW]=設計電影院 2.39:1 [ 2484x1040 , 96dpi RGB , 8bit ] Type=Link URL[$e]=.source/Designcinema2.39_1_2484x1040_96dpiRGB_8bit_.kra X-KDE-Hidden=false diff --git a/krita/data/templates/design/DesignpresentationA3Landscape_4960x3508_300dpiRGB_8bit_.desktop b/krita/data/templates/design/DesignpresentationA3Landscape_4960x3508_300dpiRGB_8bit_.desktop index 4ed5048ee7..ed0010c527 100644 --- a/krita/data/templates/design/DesignpresentationA3Landscape_4960x3508_300dpiRGB_8bit_.desktop +++ b/krita/data/templates/design/DesignpresentationA3Landscape_4960x3508_300dpiRGB_8bit_.desktop @@ -1,37 +1,38 @@ [Desktop Entry] Icon=template_DIN_A3_landscape Name=Design presentation A3 Landscape [ 4960x3508 , 300dpi RGB , 8bit ] Name[bs]=Design prezentacija A3 položeno [ 4960x3508 , 300dpi RGB , 8bit ] Name[ca]=Disseny de presentació A3 apaïsada [4960x3508, 300 ppp amb RGB, 8 bits] Name[ca@valencia]=Disseny de presentació A3 apaïsada [4960x3508, 300 ppp amb RGB, 8 bits] Name[cs]=Návrh prezentace A3 vodorovně [ 4960x3508 , 300dpi RGB , 8bit ] Name[da]=Design-præsentation A3 liggende [ 4960x3508 , 300dpi RGB , 8bit ] Name[de]=Design-Präsentation A3 Querformat [ 4960x3508 , 300dpi RGB , 8bit ] Name[el]=Design presentation A3 Landscape [ 4960x3508 , 300dpi RGB , 8bit ] Name[en_GB]=Design presentation A3 Landscape [ 4960x3508 , 300dpi RGB , 8bit ] Name[es]=Diseño de presentación A3 apaisado [ 4960x3508 , 300dpi RGB , 8bit ] Name[et]=Disainesitlus A3 rõhtpaigutusega [ 4960x3508 , 300dpi RGB , 8bit ] Name[eu]=Aurkezpen-diseinua A3 paisaia [4960 x 3508, 300 dpi GBU, 8 bit] +Name[fi]=Ruutusuunnitelma vaaka-A3 [4960 × 3508, 300 dpi RGB, 8 bit] Name[fr]=Style présentation A3 paysage [ 4960x3508, 300dpi RGB, 8bit ] Name[gl]=Deseño de presentación A3 apaisada (4960×3508, 300 dpi RGB, 8 bits) Name[hu]=Tervező bemutató A3 fekvő [ 4960x3508 , 300dpi RGB , 8bit ] Name[is]=Hanna kynningu A3 lárétt : [ 4960x3508 , 300pát RGB , 8bita ] Name[it]=Stile di presentazione A3 orizzontale [ 4960x3508 , 300dpi RGB , 8bit ] Name[ja]=プレゼンテーション A3 横向き [ 4960x3508、300dpi RGB、8 ビット ] Name[kk]=Презентация пішімі A3 жатық [ 4960x3508 , 300 н/д RGB , 8бит ] Name[nb]=Design presentasjon A3 liggende [ 4960x3508 , 300dpi RGB , 8bit ] Name[nl]=Design presentatie A3 Landschap [ 4960x3508 , 300dpi RGB , 8bit ] Name[pl]=Prezentacja projekcyjna A3 poziomo [ 4960x3508 , 300dpi RGB , 8bit ] Name[pt]=Desenho de apresentação A3 em Paisagem [ 4960x3508 , 300ppp RGB , 8-bits ] Name[pt_BR]=Design de apresentação A3 paisagem [ 4960x3508, 300dpi RGB, 8bits ] Name[ru]=Дизайн презентации A3 Ландшафтный [ 4960x3508 , 300dpi RGB , 8bit ] Name[sk]=Dizajn prezentácia A3 krajinka [ 4960x3508 , 300dpi RGB , 8bit ] Name[sv]=Design presentation A3 landskap [ 4960x3508, 300 punkter/tum RGB, 8 bitar ] Name[tr]=A3 Yatay sunum tasarla [ 4960x3508 , 300dpi RGB , 8bit ] Name[uk]=Компонування презентації, A3, альбомна [4960⨯3508, 300 т./д., RGB, 8 бітів] Name[x-test]=xxDesign presentation A3 Landscape [ 4960x3508 , 300dpi RGB , 8bit ]xx Name[zh_CN]=A3 横版设计模板 [ 4960x3508 像素, 300dpi RGB , 8 位] Name[zh_TW]=設計圖像 A3 風景畫 [ 4960x3508 , 300dpi RGB , 8bit ] Type=Link URL[$e]=.source/DesignpresentationA3Landscape_4960x3508_300dpiRGB_8bit_.kra X-KDE-Hidden=false diff --git a/krita/data/templates/design/DesignpresentationA4portrait_2480x3508,300dpiRGB_8bit_.desktop b/krita/data/templates/design/DesignpresentationA4portrait_2480x3508,300dpiRGB_8bit_.desktop index 7256d7610c..d3a440ace5 100644 --- a/krita/data/templates/design/DesignpresentationA4portrait_2480x3508,300dpiRGB_8bit_.desktop +++ b/krita/data/templates/design/DesignpresentationA4portrait_2480x3508,300dpiRGB_8bit_.desktop @@ -1,37 +1,38 @@ [Desktop Entry] Icon=template_DIN_A4_portrait Name=Design presentation A4 portrait [ 2480x3508 , 300dpi RGB , 8bit ] Name[bs]=Design prezentacija A4 uspravno [ 2480x3508 , 300dpi RGB , 8bit ] Name[ca]=Disseny de presentació A4 vertical [2480x3508, 300 ppp amb RGB, 8 bits] Name[ca@valencia]=Disseny de presentació A4 vertical [2480x3508, 300 ppp amb RGB, 8 bits] Name[cs]=Návrh prezentace A4 svisle [ x3508 , 300dpi RGB , 8bit ] Name[da]=Design-præsentation A4 stående [ x3508 , 300dpi RGB , 8bit ] Name[de]=Design-Präsentation A4 Hochformat [ 2480x3508 , 300dpi RGB , 8bit ] Name[el]=Design presentation A4 portrait [ 2480x3508 , 300dpi RGB , 8bit ] Name[en_GB]=Design presentation A4 portrait [ 2480x3508 , 300dpi RGB , 8bit ] Name[es]=Diseño de presentación A4 retrato [ 2480x3508 , 300dpi RGB , 8bit ] Name[et]=Disainesitlus A4 püstpaigutusega [ 2480x3508 , 300dpi RGB , 8bit ] Name[eu]=Aurkezpen-diseinua A4 erretratua [2480 x 3508, 300 dpi GBU, 8 bit] +Name[fi]=Ruutusuunnitelma pysty-A4 [2480×3508, 300 dpi RGB, 8 bit] Name[fr]=Style présentation A4 portrait [ 2480x3508, 300dpi RGB, 8bit ] Name[gl]=Deseño de presentación A4 vertical (2480×3508, 300 dpi RGB, 8 bits) Name[hu]=Tervező bemutató A4 álló [ 2480x3508 , 300dpi RGB , 8bit ] Name[is]=Hanna kynningu A4 lóðrétt : [ 2480x3508 , 300pát RGB , 8bita ] Name[it]=Stile di presentazione A4 verticale [ 2480x3508 , 300dpi RGB , 8bit ] Name[ja]=プレゼンテーション A4 縦向き [ 2480x3508、300dpi RGB、8 ビット ] Name[kk]=Презентация пішімі A4 жатық [ 2460x3508 , 300 н/д RGB , 8бит ] Name[nb]=Design presentasjon A4 stående [ x3508 , 300dpi RGB , 8bit ] Name[nl]=Design presentatie A4 portret [ 2480x3508 , 300dpi RGB , 8bit ] Name[pl]=Prezentacja projekcyjna A4 pionowo [ 2480x3508 , 300dpi RGB , 8bit ] Name[pt]=Desenho de apresentação A4 em Paisagem [ 2480x3508 , 300ppp RGB , 8-bits ] Name[pt_BR]=Design de apresentação A4 retrato [ 2480x3508, 300dpi RGB, 8bits ] Name[ru]=Дизайн презентации A4 Портретный [ 2480x3508 , 300dpi RGB , 8bit ] Name[sk]=Dizajn prezentácia A4 portrét [ 2480x3508 , 300dpi RGB , 8bit ] Name[sv]=Design presentation A4 porträtt [ 2480x3508, 300 punkter/tum RGB, 8 bitar ] Name[tr]=A4 dikey sunum tasarla [ 2480x3508 , 300dpi RGB , 8bit ] Name[uk]=Компонування презентації, A4, книжкова [2480x3508, 300 т./д., RGB, 8 бітів] Name[x-test]=xxDesign presentation A4 portrait [ 2480x3508 , 300dpi RGB , 8bit ]xx Name[zh_CN]=A4 竖版设计模板 [ 2480x3508 像素, 300dpi RGB , 8 位 ] Name[zh_TW]=設計圖像 A4 肖像 [ 2480x3508 , 300dpi RGB , 8bit ] Type=Link URL[$e]=.source/DesignpresentationA4portrait_2480x3508_300dpiRGB_8bit_.kra X-KDE-Hidden=false diff --git a/krita/data/templates/design/DesignpresentationA4portrait_2480x3508_300dpiRGB_8bit_.desktop b/krita/data/templates/design/DesignpresentationA4portrait_2480x3508_300dpiRGB_8bit_.desktop index 7256d7610c..d3a440ace5 100644 --- a/krita/data/templates/design/DesignpresentationA4portrait_2480x3508_300dpiRGB_8bit_.desktop +++ b/krita/data/templates/design/DesignpresentationA4portrait_2480x3508_300dpiRGB_8bit_.desktop @@ -1,37 +1,38 @@ [Desktop Entry] Icon=template_DIN_A4_portrait Name=Design presentation A4 portrait [ 2480x3508 , 300dpi RGB , 8bit ] Name[bs]=Design prezentacija A4 uspravno [ 2480x3508 , 300dpi RGB , 8bit ] Name[ca]=Disseny de presentació A4 vertical [2480x3508, 300 ppp amb RGB, 8 bits] Name[ca@valencia]=Disseny de presentació A4 vertical [2480x3508, 300 ppp amb RGB, 8 bits] Name[cs]=Návrh prezentace A4 svisle [ x3508 , 300dpi RGB , 8bit ] Name[da]=Design-præsentation A4 stående [ x3508 , 300dpi RGB , 8bit ] Name[de]=Design-Präsentation A4 Hochformat [ 2480x3508 , 300dpi RGB , 8bit ] Name[el]=Design presentation A4 portrait [ 2480x3508 , 300dpi RGB , 8bit ] Name[en_GB]=Design presentation A4 portrait [ 2480x3508 , 300dpi RGB , 8bit ] Name[es]=Diseño de presentación A4 retrato [ 2480x3508 , 300dpi RGB , 8bit ] Name[et]=Disainesitlus A4 püstpaigutusega [ 2480x3508 , 300dpi RGB , 8bit ] Name[eu]=Aurkezpen-diseinua A4 erretratua [2480 x 3508, 300 dpi GBU, 8 bit] +Name[fi]=Ruutusuunnitelma pysty-A4 [2480×3508, 300 dpi RGB, 8 bit] Name[fr]=Style présentation A4 portrait [ 2480x3508, 300dpi RGB, 8bit ] Name[gl]=Deseño de presentación A4 vertical (2480×3508, 300 dpi RGB, 8 bits) Name[hu]=Tervező bemutató A4 álló [ 2480x3508 , 300dpi RGB , 8bit ] Name[is]=Hanna kynningu A4 lóðrétt : [ 2480x3508 , 300pát RGB , 8bita ] Name[it]=Stile di presentazione A4 verticale [ 2480x3508 , 300dpi RGB , 8bit ] Name[ja]=プレゼンテーション A4 縦向き [ 2480x3508、300dpi RGB、8 ビット ] Name[kk]=Презентация пішімі A4 жатық [ 2460x3508 , 300 н/д RGB , 8бит ] Name[nb]=Design presentasjon A4 stående [ x3508 , 300dpi RGB , 8bit ] Name[nl]=Design presentatie A4 portret [ 2480x3508 , 300dpi RGB , 8bit ] Name[pl]=Prezentacja projekcyjna A4 pionowo [ 2480x3508 , 300dpi RGB , 8bit ] Name[pt]=Desenho de apresentação A4 em Paisagem [ 2480x3508 , 300ppp RGB , 8-bits ] Name[pt_BR]=Design de apresentação A4 retrato [ 2480x3508, 300dpi RGB, 8bits ] Name[ru]=Дизайн презентации A4 Портретный [ 2480x3508 , 300dpi RGB , 8bit ] Name[sk]=Dizajn prezentácia A4 portrét [ 2480x3508 , 300dpi RGB , 8bit ] Name[sv]=Design presentation A4 porträtt [ 2480x3508, 300 punkter/tum RGB, 8 bitar ] Name[tr]=A4 dikey sunum tasarla [ 2480x3508 , 300dpi RGB , 8bit ] Name[uk]=Компонування презентації, A4, книжкова [2480x3508, 300 т./д., RGB, 8 бітів] Name[x-test]=xxDesign presentation A4 portrait [ 2480x3508 , 300dpi RGB , 8bit ]xx Name[zh_CN]=A4 竖版设计模板 [ 2480x3508 像素, 300dpi RGB , 8 位 ] Name[zh_TW]=設計圖像 A4 肖像 [ 2480x3508 , 300dpi RGB , 8bit ] Type=Link URL[$e]=.source/DesignpresentationA4portrait_2480x3508_300dpiRGB_8bit_.kra X-KDE-Hidden=false diff --git a/krita/data/templates/design/Designscreen4_3_2250x1680_96dpiRGB_8bit_.desktop b/krita/data/templates/design/Designscreen4_3_2250x1680_96dpiRGB_8bit_.desktop index 824dbed932..45d7f87e4c 100644 --- a/krita/data/templates/design/Designscreen4_3_2250x1680_96dpiRGB_8bit_.desktop +++ b/krita/data/templates/design/Designscreen4_3_2250x1680_96dpiRGB_8bit_.desktop @@ -1,37 +1,38 @@ [Desktop Entry] Icon=template_ratio_43 Name=Design screen 4:3 [ 2250x1680 , 96dpi RGB , 8bit ] Name[bs]=Design ekran 4:3 [ 2250x1680 , 96dpi RGB , 8bit ] Name[ca]=Disseny de pantalla 4:3 [2250x1680, 96 ppp amb RGB, 8 bits] Name[ca@valencia]=Disseny de pantalla 4:3 [2250x1680, 96 ppp amb RGB, 8 bits] Name[cs]=Návrh obrazovka 4:3 [ 2250x1680 , 96dpi RGB , 8bit ] Name[da]=Design-skærm 4:3 [ 2250x1680 , 96dpi RGB , 8bit ] Name[de]=Design-Bildschirm 4:3 [ 2250x1680 , 96dpi RGB , 8bit ] Name[el]=Design screen 4:3 [ 2250x1680 , 96dpi RGB , 8bit ] Name[en_GB]=Design screen 4:3 [ 2250x1680 , 96dpi RGB , 8bit ] Name[es]=Diseño de pantalla 4:3 [ 2250x1680 , 96dpi RGB , 8bit ] Name[et]=Disainekraan 4:3 [ 2250x1680 , 96dpi RGB , 8bit ] Name[eu]=Diseinu-pantaila 4:3 [2250 x 1680, 96 dpi GBU, 8 bit] +Name[fi]=Ruutusuunnitelma 4 : 3 [2250 × 1680, 96 dpi RGB, 8 bit] Name[fr]=Style écran 4:3 [ 2250x1680, 96dpi RGB, 8bit ] Name[gl]=Deseño de pantalla 4:3 (2250×1680, 96 dpi RGB, 8 bits) Name[hu]=Tervező kijelző 4:3 [ 2250x1680 , 96dpi RGB , 8bit ] Name[is]=Hanna skjá 4:3 [ 2250x1680 , 96pát RGB , 8bita ] Name[it]=Stile di disegno 4:3 [ 2250x1680 , 96dpi RGB , 8bit ] Name[ja]=スクリーン 4:3 [ 2250x1680、96dpi RGB、8ビット ] Name[kk]=Экран пішімі 4:3 [ 2250x1680 , 96 н/д RGB , 8бит ] Name[nb]=Design skjerm 4:3 [ 2250x1680 , 96dpi RGB , 8bit ] Name[nl]=Design screen 4:3 [ 2250x1680 , 96dpi RGB , 8bit ] Name[pl]=Ekran projekcyjny 4:3 [ 2250x1680 , 96dpi RGB , 8bit ] Name[pt]=Desenho de ecrã 4:3 [ 2250x1680 , 96ppp RGB , 8-bits ] Name[pt_BR]=Design de tela 4:3 [ 2250x1680, 96dpi RGB, 8bits ] Name[ru]=Дизайн экрана 4:3 [ 2250x1680 , 96dpi RGB , 8bit ] Name[sk]=Dizajn obrazovka 4:3 [ 2250x1680 , 96dpi RGB , 8bit ] Name[sv]=Design skärm 4:3 [ 2250x1680, 96 punkter/tum RGB, 8 bitar ] Name[tr]=Ekran tasarla 4:3 [ 2250x1680 , 96dpi RGB , 8bit ] Name[uk]=Компонування екрана 4:3 [2250⨯1680, 96 т./д., RGB, 8 бітів] Name[x-test]=xxDesign screen 4:3 [ 2250x1680 , 96dpi RGB , 8bit ]xx Name[zh_CN]=4:3 屏幕设计模板 [ 2250x1680 像素, 96dpi RGB , 8 位] Name[zh_TW]=設計螢幕 4:3 [ 2250x1680 , 96dpi RGB , 8bit ] Type=Link URL[$e]=.source/Designscreen4_3_2250x1680_96dpiRGB_8bit_.kra X-KDE-Hidden=false diff --git a/krita/data/templates/design/web_design.desktop b/krita/data/templates/design/web_design.desktop index db2c9d7476..b479a76054 100644 --- a/krita/data/templates/design/web_design.desktop +++ b/krita/data/templates/design/web_design.desktop @@ -1,36 +1,37 @@ [Desktop Entry] Icon=template_web_design Name=Web Design [ 2160x1440 , 72ppi RGB , 8bit ] Name[ar]=تصميم وبّ [ ٢١٦٠×١٤٤٠ ، ٧٢ بكسل/بوصة ، ٨ بتّ ] Name[bs]=Web dizajn [ 2160x1440 , 72ppi RGB , 8bit ] Name[ca]=Disseny web [2160x1440, 72 ppp amb RGB, 8 bits] Name[ca@valencia]=Disseny web [2160x1440, 72 ppp amb RGB, 8 bits] Name[cs]=Návrh webu [ 2160x1440 , 72ppi RGB , 8bit ] Name[da]=Webdesign [ 2160x1440 , 72ppi RGB , 8bit ] Name[de]=Web-Design [ 2160x1440 , 72ppi RGB , 8bit ] Name[el]=Σχεδίαση διαδικτυακών τόπων [ 2160x1440 , 72ppi RGB , 8bit ] Name[en_GB]=Web Design [ 2160x1440 , 72ppi RGB , 8bit ] Name[es]=Diseño de web 4:3 [ 2160x1440 , 72ppi RGB , 8bit ] Name[et]=Veebidisain [ 2160x1440, 72ppi RGB, 8-bitine ] Name[eu]=Web-diseinua [ 2160x1440 , 72ppi GBU , 8bit ] +Name[fi]=Verkkosuunnitelma [2160 × 1440, 72 ppi RGB, 8 bit] Name[fr]=Style écran [ 2160x1440, 72ppi RGB, 8bit ] Name[gl]=Deseño web (2160×1440, 72 ppi RGB, 8 bits) Name[is]=Vefhönnun [ 2160x1440 , 72pát RGB , 8bita ] Name[it]=Progettazione web [ 2160x1440 , 72ppi RGB , 8bit ] Name[ja]=ウェブデザイン [ 2160x1440、72ppi RGB、8 ビット ] Name[nb]=Web Design [ 2160x1440 , 72ppi RGB , 8bit ] Name[nl]=Webontwerp [ 2160x1440 , 72ppi RGB , 8bit ] Name[pl]=Projekt sieciowy [ 2160x1440 , 72ppi RGB , 8bit ] Name[pt]=Desenho na Web [ 2160x1440 , 72ppp RGB , 8-bits ] Name[pt_BR]=Web Design [ 2160x1440 , 72ppi RGB , 8bits ] Name[ru]=Веб-дизайн [ 2160x1440 , 72ppi RGB , 8 бит ] Name[sk]=Webový dizajn [ 2160x1440 , 72ppi RGB , 8bit ] Name[sv]=Webbdesign [ 2160x1440, 72 punkter/tum RGB, 8 bitar ] Name[tr]=Web Tasarımı [ 2160x1440 , 72ppi RGB , 8bit ] Name[uk]=Вебдизайн [2160⨯1440, 72 т./д., RGB, 8 бітів] Name[x-test]=xxWeb Design [ 2160x1440 , 72ppi RGB , 8bit ]xx Name[zh_CN]=网页设计模板 [ 2160x1440 像素, 72ppi RGB , 8 位 ] Name[zh_TW]=網頁設計 [ 2160x1440 , 72ppi RGB , 8bit ] Type=Link URL[$e]=.source/web_design.kra X-KDE-Hidden=false diff --git a/krita/data/templates/texture/Texture1024x10248bitsrgb.desktop b/krita/data/templates/texture/Texture1024x10248bitsrgb.desktop index bb31a169bf..388131bc8c 100644 --- a/krita/data/templates/texture/Texture1024x10248bitsrgb.desktop +++ b/krita/data/templates/texture/Texture1024x10248bitsrgb.desktop @@ -1,35 +1,36 @@ [Desktop Entry] Icon=template_texture Name=Texture 1024x1024 8bit srgb Name[bs]=Tekstura 1024x1024 8bit srgb Name[ca]=Textura 1024x1024 de 8 bits amb SRGB Name[ca@valencia]=Textura 1024x1024 de 8 bits amb SRGB Name[cs]=Textura 1024x1024 8bit srgb Name[da]=Tekstur 1024x1024 8bit srgb Name[de]=Textur 1024x1024 8bit srgb Name[el]=Υφή 1024x1024 8bit srgb Name[en_GB]=Texture 1024x1024 8bit srgb Name[es]=Textura 1024x1024 8bits srgb Name[et]=Tekstuur 1024x1024 8bit srgb Name[eu]=Ehundura 1024x1024 8bit sRGB +Name[fi]=Pintakuvio 1024 × 1024 8 bit SRGB Name[fr]=Texture 1024x1024 8bit srgb Name[gl]=Textura de 1024×1024 e 8 bits SRGB Name[is]=Efnisáferð 1024x1024 8bita srgb Name[it]=Trama 1024x1024 8bit srgb Name[ja]=テクスチャ 1024x1024 8 ビット sRGB Name[nb]=Tekstur 1024x1024 8bit srgb Name[nl]=Textuur 1024x1024 8bit srgb Name[pl]=Tekstura 1024x1024 8bit srgb Name[pt]=Textura 1024x1024 8-bits sRGB Name[pt_BR]=Textura 1024x1024 8-bits sRGB Name[ru]=Текстура 1024x1024 8 бит srgb Name[sk]=Textúra 1024x1024 8bit srgb Name[sv]=Struktur 1024 x 1024 8-bitar SRGB Name[tr]=Doku 1024x1024 8bit srgb Name[uk]=Текстура 1024⨯1024, 8-бітова, srgb Name[x-test]=xxTexture 1024x1024 8bit srgbxx Name[zh_CN]=1024x1024 纹理模板 8位 sRGB 色彩空间 Name[zh_TW]=紋理 1024x1024 8位元 srgb Type=Link URL[$e]=.source/Texture1024x10248bitsrgb.kra X-KDE-Hidden=false diff --git a/krita/data/templates/texture/Texture1k32bitscalar.desktop b/krita/data/templates/texture/Texture1k32bitscalar.desktop index a3c90b5443..c2de545c0f 100755 --- a/krita/data/templates/texture/Texture1k32bitscalar.desktop +++ b/krita/data/templates/texture/Texture1k32bitscalar.desktop @@ -1,37 +1,38 @@ [Desktop Entry] Icon=template_texture Name=Texture 1k 32bit scalar Name[bs]=Tekstura 1k 32bit scalar Name[ca]=Textura 1k de 32 bits escalar Name[ca@valencia]=Textura 1k de 32 bits escalar Name[cs]=Textura 1k 32bit skalární Name[da]=Tekstur 1k 32bit scalar Name[de]=Textur 1k 32bit scalar Name[el]=Υφή 1k 32bit βαθμωτό Name[en_GB]=Texture 1k 32bit scalar Name[es]=Textura 1k 32 bit escalar Name[et]=Tekstuur 1k 32bit skalaar Name[eu]=Ehundura 1k 32bit eskalarra +Name[fi]=Pintakuvio 1k 32 bit skalaarinen Name[fr]=Texture 1k 32bit scalaire Name[gl]=Textura de 1k e 32 bits escalar Name[hu]=Textúra 1k 32bit skalár Name[is]=Efnisáferð 1k 32bita scalar Name[it]=Trama 1k 32bit scalare Name[ja]=テクスチャ 1k 32 ビットスカラー Name[kk]=Текстура 1k 32 бит скаляр Name[nb]=Tekstur 1k 32bit skalar Name[nl]=Textuur 1k 32bit scalar Name[pl]=Tekstura 1k 32bit skalar Name[pt]=Textura 1k 32-bits escalar Name[pt_BR]=Textura 1k 32bits escalar Name[ru]=Текстура 1k 32 бит scalar Name[sk]=Textúra 1k 32bit skalár Name[sv]=Struktur 1k 32-bitar skalär Name[tr]=Doku 1k 32bit sayısal Name[uk]=Текстура 1k, 32-бітова, скалярна Name[x-test]=xxTexture 1k 32bit scalarxx Name[zh_CN]=1K 纹理模板 32 位 Scalar 色彩空间 Name[zh_TW]=紋理 1k 32位元 scalar Type=Link URL[$e]=.source/Texture1k32bitscalar.kra X-KDE-Hidden=false diff --git a/krita/data/templates/texture/Texture1k8bitsrgb.desktop b/krita/data/templates/texture/Texture1k8bitsrgb.desktop index 4d99b39a46..2d2dd6598c 100755 --- a/krita/data/templates/texture/Texture1k8bitsrgb.desktop +++ b/krita/data/templates/texture/Texture1k8bitsrgb.desktop @@ -1,37 +1,38 @@ [Desktop Entry] Icon=template_texture Name=Texture 1k 8bit srgb Name[bs]=Tekstura 1k 8bit srgb Name[ca]=Textura 1k de 8 bits amb SRGB Name[ca@valencia]=Textura 1k de 8 bits amb SRGB Name[cs]=Textura 1k 8bit srgb Name[da]=Tekstur 1k 8bit srgb Name[de]=Textur 1k 8bit srgb Name[el]=Υφή 1k 8bit srgb Name[en_GB]=Texture 1k 8bit srgb Name[es]=Textura 1k 8bit srgb Name[et]=Tekstuur 1k 8bit srgb Name[eu]=Ehundura 1k 8bit sGBU +Name[fi]=Pintakuvio 1k 8 bit SRGB Name[fr]=Texture 1k 8bit srgb Name[gl]=Textura de 1k e 8 bits SRGB Name[hu]=Textúra 1k 8bit srgb Name[is]=Efnisáferð 1k 8bita srgb Name[it]=Trama 1k 8bit srgb Name[ja]=テクスチャ 1k 8 ビット sRGB Name[kk]=Текстура 1k 8 бит srgb Name[nb]=Tekstur 1k 8bit srgb Name[nl]=Textuur 1k 8bit srgb Name[pl]=Tekstura 1k 8bit srgb Name[pt]=Textura 1k 8-bits sRGB Name[pt_BR]=Textura 1k 8bits sRGB Name[ru]=Текстура 1k 8 бит srgb Name[sk]=Textúra 1k 8bit srgb Name[sv]=Struktur 1k 8-bitar SRGB Name[tr]=Doku 1k 8bit srgb Name[uk]=Текстура 1k, 8-бітова, srgb Name[x-test]=xxTexture 1k 8bit srgbxx Name[zh_CN]=1K 纹理模板 8 位 sRGB 色彩空间 Name[zh_TW]=紋理 1k 8位元 srgb Type=Link URL[$e]=.source/Texture1k8bitsrgb.kra X-KDE-Hidden=false diff --git a/krita/data/templates/texture/Texture2048x20488bitsrgb.desktop b/krita/data/templates/texture/Texture2048x20488bitsrgb.desktop index 37d89e8e2b..f92ea653c9 100644 --- a/krita/data/templates/texture/Texture2048x20488bitsrgb.desktop +++ b/krita/data/templates/texture/Texture2048x20488bitsrgb.desktop @@ -1,35 +1,36 @@ [Desktop Entry] Icon=template_texture Name=Texture 2048x2048 8bit srgb Name[bs]=Tekstura 2048x2048 8bit srgb Name[ca]=Textura 2048x2048 de 8 bits amb SRGB Name[ca@valencia]=Textura 2048x2048 de 8 bits amb SRGB Name[cs]=Textura 2048x2048 8bit srgb Name[da]=Tekstur 2048x2048 8bit srgb Name[de]=Textur 2048x2048 8bit srgb Name[el]=Υφή 2048x2048 8bit srgb Name[en_GB]=Texture 2048x2048 8bit srgb Name[es]=Textura 2048x2048 8bits srgb Name[et]=Tekstuur 2048x2048 8bit srgb Name[eu]=Ehundura 2048x2048 8bit sGBU +Name[fi]=Pintakuvio 2048 × 2048 8 bit SRGB Name[fr]=Texture 2048x2048 8bit srgb Name[gl]=Textura de 2048×2048 e 8 bits SRGB Name[is]=Efnisáferð 2048x2048 8bita srgb Name[it]=Trama 2048x2048 8bit srgb Name[ja]=テクスチャ 2048x2048 8 ビット sRGB Name[nb]=Tekstur 2048x2048 8bit srgb Name[nl]=Textuur 2048x2048 8bit srgb Name[pl]=Tekstura 2048x2048 8bit srgb Name[pt]=Textura 2048x2048 8-bits sRGB Name[pt_BR]=Textura 2048x2048 8bits sRGB Name[ru]=Текстура 2048x2048 8 бит srgb Name[sk]=Textúra 2048x2048 8bit srgb Name[sv]=Struktur 2048 x 2048 8-bitar SRGB Name[tr]=Doku 2048x2048 8bit srgb Name[uk]=Текстура 2048⨯2048, 8-бітова, srgb Name[x-test]=xxTexture 2048x2048 8bit srgbxx Name[zh_CN]=2048x2048 纹理模板 8 位 sRGB 色彩空间 Name[zh_TW]=紋理 2048x2048 8位元 srgb Type=Link URL[$e]=.source/Texture2048x20488bitsrgb.kra X-KDE-Hidden=false diff --git a/krita/data/templates/texture/Texture256x2568bitsrgb.desktop b/krita/data/templates/texture/Texture256x2568bitsrgb.desktop index 8a23f9f519..24bc6f44ff 100644 --- a/krita/data/templates/texture/Texture256x2568bitsrgb.desktop +++ b/krita/data/templates/texture/Texture256x2568bitsrgb.desktop @@ -1,35 +1,36 @@ [Desktop Entry] Icon=template_texture Name=Texture 256x256 8bit srgb Name[bs]=Tekstura 256x256 8bit srgb Name[ca]=Textura 256x256 de 8 bits amb SRGB Name[ca@valencia]=Textura 256x256 de 8 bits amb SRGB Name[cs]=Textura 256x256 8bit srgb Name[da]=Tekstur 256x256 8bit srgb Name[de]=Textur 256x256 8bit srgb Name[el]=Υφή 256x256 8bit srgb Name[en_GB]=Texture 256x256 8bit srgb Name[es]=Textura 256x256 8bits srgb Name[et]=Tekstuur 256x256 8bit srgb Name[eu]=Ehundura 256x256 8bit sGBU +Name[fi]=Pintakuvio 256 × 256 8 bit SRGB Name[fr]=Texture 256x256 8bit srgb Name[gl]=Textura de 256×256 e 8 bits SRGB Name[is]=Efnisáferð 256x256 8bita srgb Name[it]=Trama 256x256 8bit srgb Name[ja]=テクスチャ 256x256 8 ビット sRGB Name[nb]=Tekstur 256x256 8bit srgb Name[nl]=Textuur 256x256 8bit srgb Name[pl]=Tekstura 256x256 8bit srgb Name[pt]=Textura 256x256 8-bits sRGB Name[pt_BR]=Textura 256x256 8bits sRGB Name[ru]=Текстура 256x256 8 бит srgb Name[sk]=Textúra 256x256 8bit srgb Name[sv]=Struktur 256 x 256 8-bitar SRGB Name[tr]=Doku 256x256 8bit srgb Name[uk]=Текстура 256⨯256, 8-бітова, srgb Name[x-test]=xxTexture 256x256 8bit srgbxx Name[zh_CN]=256x256 纹理模板 8 位 sRGB 色彩空间 Name[zh_TW]=紋理 256x256 8位元 srgb Type=Link URL[$e]=.source/Texture256x2568bitsrgb.kra X-KDE-Hidden=false diff --git a/krita/data/templates/texture/Texture2k32bitscalar.desktop b/krita/data/templates/texture/Texture2k32bitscalar.desktop index dcf819e9df..bbf713eb77 100755 --- a/krita/data/templates/texture/Texture2k32bitscalar.desktop +++ b/krita/data/templates/texture/Texture2k32bitscalar.desktop @@ -1,37 +1,38 @@ [Desktop Entry] Icon=template_texture Name=Texture 2k 32bit scalar Name[bs]=Tekstura 2k 32bit scalar Name[ca]=Textura 2k de 32 bits escalar Name[ca@valencia]=Textura 2k de 32 bits escalar Name[cs]=Textura 2k 32bit skalární Name[da]=Tekstur 2k 32bit scalar Name[de]=Textur 2k 32bit scalar Name[el]=Υφή 2k 32bit βαθμωτό Name[en_GB]=Texture 2k 32bit scalar Name[es]=Textura 2k 32bit escalar Name[et]=Tekstuur 2k 32bit skalaar Name[eu]=Ehundura 2k 32bit eskalarra +Name[fi]=Pintakuvio 2k 32 bit skalaarinen Name[fr]=Texture 2k 32bit scalaire Name[gl]=Textura de 2k e 32 bits escalar Name[hu]=Textúra 2k 32bit skalár Name[is]=Efnisáferð 2k 32bita scalar Name[it]=Trama 2k 32bit scalare Name[ja]=テクスチャ 2k 32 ビットスカラー Name[kk]=Текстура 2k 32 бит скаляр Name[nb]=Tekstur 2k 32bit skalar Name[nl]=Textuur 2k 32bit scalar Name[pl]=Tekstura 2k 32bit skalar Name[pt]=Textura 2k 32-bits escalar Name[pt_BR]=Textura 2k 32bits escalar Name[ru]=Текстура 2k 32 бит scalar Name[sk]=Textúra 2k 32bit skalár Name[sv]=Struktur 2k 32-bitar skalär Name[tr]=Doku 2k 32bit sayısal Name[uk]=Текстура 2k, 32-бітова, скалярна Name[x-test]=xxTexture 2k 32bit scalarxx Name[zh_CN]=2K 纹理模板 32 位 Scalar 色彩空间 Name[zh_TW]=紋理 2k 32位元 scalar Type=Link URL[$e]=.source/Texture2k32bitscalar.kra X-KDE-Hidden=false diff --git a/krita/data/templates/texture/Texture2k8bitsrgb.desktop b/krita/data/templates/texture/Texture2k8bitsrgb.desktop index afb643a98d..ead9ba4541 100755 --- a/krita/data/templates/texture/Texture2k8bitsrgb.desktop +++ b/krita/data/templates/texture/Texture2k8bitsrgb.desktop @@ -1,37 +1,38 @@ [Desktop Entry] Icon=template_texture Name=Texture 2k 8bit srgb Name[bs]=Tekstura 2k 8bit srgb Name[ca]=Textura 2k de 8 bits amb SRGB Name[ca@valencia]=Textura 2k de 8 bits amb SRGB Name[cs]=Textura 2k 8bit srgb Name[da]=Tekstur 2k 8bit srgb Name[de]=Textur 2k 8bit srgb Name[el]=Υφή 2k 8bit srgb Name[en_GB]=Texture 2k 8bit srgb Name[es]=Textura 2k 8bit srgb Name[et]=Tekstuur 2k 8bit srgb Name[eu]=Ehundura 2k 8bit sGBU +Name[fi]=Pintakuvio 2k 8 bit SRGB Name[fr]=Texture 2k 8bit srgb Name[gl]=Textura de 2k e 8 bits SRGB Name[hu]=Textúra 2k 8bit srgb Name[is]=Efnisáferð 2k 8bita srgb Name[it]=Trama 2k 8bit srgb Name[ja]=テクスチャ 2k 8 ビット sRGB Name[kk]=Текстура 2k 8 бит srgb Name[nb]=Tekstur 2k 8bit srgb Name[nl]=Textuur 2k 8bit srgb Name[pl]=Tekstura 2k 8bit srgb Name[pt]=Textura 2k 8-bits sRGB Name[pt_BR]=Textura 2k 8bits sRGB Name[ru]=Текстура 2k 8 бит srgb Name[sk]=Textúra 2k 8bit srgb Name[sv]=Struktur 2k 8-bitar SRGB Name[tr]=Doku 2k 8bit srgb Name[uk]=Текстура 2k, 8-бітова, srgb Name[x-test]=xxTexture 2k 8bit srgbxx Name[zh_CN]=2K 纹理模板 8 位 sRGB 色彩空间 Name[zh_TW]=紋理 2k 8位元 srgb Type=Link URL[$e]=.source/Texture2k8bitsrgb.kra X-KDE-Hidden=false diff --git a/krita/data/templates/texture/Texture4096x40968bitsrgb.desktop b/krita/data/templates/texture/Texture4096x40968bitsrgb.desktop index d6195e00dd..48d5250927 100644 --- a/krita/data/templates/texture/Texture4096x40968bitsrgb.desktop +++ b/krita/data/templates/texture/Texture4096x40968bitsrgb.desktop @@ -1,35 +1,36 @@ [Desktop Entry] Icon=template_texture Name=Texture 4096x4096 8bit srgb Name[bs]=Tekstura 4096x4096 8bit srgb Name[ca]=Textura 4096x4096 de 8 bits amb SRGB Name[ca@valencia]=Textura 4096x4096 de 8 bits amb SRGB Name[cs]=Textura 4096x4096 8bit srgb Name[da]=Tekstur 4096x4096 8bit srgb Name[de]=Textur 4096x4096 8bit srgb Name[el]=Υφή 4096x4096 8bit srgb Name[en_GB]=Texture 4096x4096 8bit srgb Name[es]=Textura 4096x4096 8bits srgb Name[et]=Tekstuur 4096x4096 8bit srgb Name[eu]=Ehundura 4096x4096 8bit sGBU +Name[fi]=Pintakuvio 4096 × 4096 8 bit SRGB Name[fr]=Texture 4096x4096 8bit srgb Name[gl]=Textura de 4096×4096 e 8 bits SRGB Name[is]=Efnisáferð 4096x4096 8bita srgb Name[it]=Trama 4096x4096 8bit srgb Name[ja]=テクスチャ 4096x4096 8 ビット sRGB Name[nb]=Tekstur 4096x4096 8bit srgb Name[nl]=Textuur 4096x4096 8bit srgb Name[pl]=Tekstura 4096x4096 8bit srgb Name[pt]=Textura 4096x4096 8-bits sRGB Name[pt_BR]=Textura 4096x4096 8bits sRGB Name[ru]=Текстура 4096x4096 8 бит srgb Name[sk]=Textúra 4096x4096 8bit srgb Name[sv]=Struktur 4096 x 4096 8-bitar SRGB Name[tr]=Doku 4096x4096 8bit srgb Name[uk]=Текстура 4096⨯4096, 8-бітова, srgb Name[x-test]=xxTexture 4096x4096 8bit srgbxx Name[zh_CN]=4096x4096 纹理模板 8 位 sRGB 色彩空间 Name[zh_TW]=紋理 4096x4096 8位元 srgb Type=Link URL[$e]=.source/Texture4096x40968bitsrgb.kra X-KDE-Hidden=false diff --git a/krita/data/templates/texture/Texture4k32bitscalar.desktop b/krita/data/templates/texture/Texture4k32bitscalar.desktop index 7bb1d25e6c..a6f8f8d1ce 100755 --- a/krita/data/templates/texture/Texture4k32bitscalar.desktop +++ b/krita/data/templates/texture/Texture4k32bitscalar.desktop @@ -1,37 +1,38 @@ [Desktop Entry] Icon=template_texture Name=Texture 4k 32bit scalar Name[bs]=Tekstura 4k 32bit scalar Name[ca]=Textura 4k de 32 bits escalar Name[ca@valencia]=Textura 4k de 32 bits escalar Name[cs]=Textura 4k 32bit skalární Name[da]=Tekstur 4k 32bit scalar Name[de]=Textur 4k 32bit scalar Name[el]=Υφή 4k 32bit βαθμωτό Name[en_GB]=Texture 4k 32bit scalar Name[es]=Textura 4k 32bit escalar Name[et]=Tekstuur 4k 32bit skalaar Name[eu]=Ehundura 4k 32bit eskalarra +Name[fi]=Pintakuvio 4k 32 bit skalaarinen Name[fr]=Texture 4k 32bit scalaire Name[gl]=Textura de 4k e 32 bits escalar Name[hu]=Textúra 4k 32bit skalár Name[is]=Efnisáferð 4k 32bita scalar Name[it]=Trama 4k 32bit scalare Name[ja]=テクスチャ 4k 32 ビットスカラー Name[kk]=Текстура 4k 32 бит скаляр Name[nb]=Tekstur 4k 32bit skalar Name[nl]=Textuur 4k 32bit scalar Name[pl]=Tekstura 4k 32bit skalar Name[pt]=Textura 4k 32-bits escalar Name[pt_BR]=Textura 4k 32bits escalar Name[ru]=Текстура 4k 32 бит scalar Name[sk]=Textúra 4k 32bit skalár Name[sv]=Struktur 4k 32-bitar skalär Name[tr]=Doku 4k 32bit sayısal Name[uk]=Текстура 4k, 32-бітова, скалярна Name[x-test]=xxTexture 4k 32bit scalarxx Name[zh_CN]=4K 纹理模板 32 位 Scalar 色彩空间 Name[zh_TW]=紋理 4k 32位元 scalar Type=Link URL[$e]=.source/Texture4k32bitscalar.kra X-KDE-Hidden=false diff --git a/krita/data/templates/texture/Texture4k8bitsrgb.desktop b/krita/data/templates/texture/Texture4k8bitsrgb.desktop index 7dca413076..81192dd93e 100755 --- a/krita/data/templates/texture/Texture4k8bitsrgb.desktop +++ b/krita/data/templates/texture/Texture4k8bitsrgb.desktop @@ -1,37 +1,38 @@ [Desktop Entry] Icon=template_texture Name=Texture 4k 8bit srgb Name[bs]=Tekstura 4k 8bit srgb Name[ca]=Textura 4k de 8 bits amb SRGB Name[ca@valencia]=Textura 4k de 8 bits amb SRGB Name[cs]=Textura 4k 8bit srgb Name[da]=Tekstur 4k 8bit srgb Name[de]=Textur 4k 8bit srgb Name[el]=Υφή 4k 8bit srgb Name[en_GB]=Texture 4k 8bit srgb Name[es]=Textura 4k 8bit srgb Name[et]=Tekstuur 4k 8bit srgb Name[eu]=Ehundura 4k 8bit sGBU +Name[fi]=Pintakuvio 4k 8 bit skalaarinen Name[fr]=Texture 4k 8bit srgb Name[gl]=Textura de 4k e 8 bits SRGB Name[hu]=Textúra 4k 8bit srgb Name[is]=Efnisáferð 4k 8bita srgb Name[it]=Trama 4k 8bit srgb Name[ja]=テクスチャ 4k 8 ビット sRGB Name[kk]=Текстура 4k 8 бит srgb Name[nb]=Tekstur 4k 8bit srgb Name[nl]=Textuur 4k 8bit srgb Name[pl]=Tekstura 4k 8bit srgb Name[pt]=Textura 4k 8-bits sRGB Name[pt_BR]=Textura 4k 8bits sRGB Name[ru]=Текстура 4k 8 бит srgb Name[sk]=Textúra 4k 8bit srgb Name[sv]=Struktur 4k 8-bitar SRGB Name[tr]=Doku 4k 8bit srgb Name[uk]=Текстура 4k, 8-бітова, srgb Name[x-test]=xxTexture 4k 8bit srgbxx Name[zh_CN]=4K 纹理模板 8 位 sRGB 色彩空间 Name[zh_TW]=紋理 4k 8位元 srgb Type=Link URL[$e]=.source/Texture4k8bitsrgb.kra X-KDE-Hidden=false diff --git a/krita/data/templates/texture/Texture512x5128bitsrgb.desktop b/krita/data/templates/texture/Texture512x5128bitsrgb.desktop index a23a80154a..8e6ae30ac6 100644 --- a/krita/data/templates/texture/Texture512x5128bitsrgb.desktop +++ b/krita/data/templates/texture/Texture512x5128bitsrgb.desktop @@ -1,35 +1,36 @@ [Desktop Entry] Icon=template_texture Name=Texture 512x512 8bit srgb Name[bs]=Tekstura 512x512 8bit srgb Name[ca]=Textura 512x512 de 8 bits amb SRGB Name[ca@valencia]=Textura 512x512 de 8 bits amb SRGB Name[cs]=Textura 512x512 8bit srgb Name[da]=Tekstur 512x512 8bit srgb Name[de]=Textur 512x512 8bit srgb Name[el]=Υφή 512x512 8bit srgb Name[en_GB]=Texture 512x512 8bit srgb Name[es]=Textura 512x512 8bits srgb Name[et]=Tekstuur 512x512 8bit srgb Name[eu]=Ehundura 512x512 8bit sGBU +Name[fi]=Pintakuvio 512 × 512 8 bit SRGB Name[fr]=Texture 512x512 8bit srgb Name[gl]=Textura de 512×512 e 8 bits SRGB Name[is]=Efnisáferð 512x512 8bita srgb Name[it]=Trama 512x512 8bit srgb Name[ja]=テクスチャ 512x512 8 ビット sRGB Name[nb]=Tekstur 512x512 8bit srgb Name[nl]=Textuur 512x512 8bit srgb Name[pl]=Tekstura 512x512 8bit srgb Name[pt]=Textura 512x512 8-bits sRGB Name[pt_BR]=Textura 512x512 8bits sRGB Name[ru]=Текстура 512x512 8 бит srgb Name[sk]=Textúra 512x512 8bit srgb Name[sv]=Struktur 512 x 512 8-bitar SRGB Name[tr]=Doku 512x512 8bit srgb Name[uk]=Текстура 512⨯512, 8-бітова, srgb Name[x-test]=xxTexture 512x512 8bit srgbxx Name[zh_CN]=512x512 纹理模板 8 位 sRGB 色彩空间 Name[zh_TW]=紋理 512x512 8位元 srgb Type=Link URL[$e]=.source/Texture512x5128bitsrgb.kra X-KDE-Hidden=false diff --git a/krita/data/templates/texture/Texture8k32bitscalar.desktop b/krita/data/templates/texture/Texture8k32bitscalar.desktop index b21eea6608..4021ce90dc 100755 --- a/krita/data/templates/texture/Texture8k32bitscalar.desktop +++ b/krita/data/templates/texture/Texture8k32bitscalar.desktop @@ -1,37 +1,38 @@ [Desktop Entry] Icon=template_texture Name=Texture 8k 32bit scalar Name[bs]=Tekstura 8k 32bit scalar Name[ca]=Textura 8k de 32 bits escalar Name[ca@valencia]=Textura 8k de 32 bits escalar Name[cs]=Textura 8k 32bit skalární Name[da]=Tekstur 8k 32bit scalar Name[de]=Textur 8k 32bit scalar Name[el]=Υφή 8k 32bit βαθμωτό Name[en_GB]=Texture 8k 32bit scalar Name[es]=Textura 8k 32 bit escalar Name[et]=Tekstuur 8k 32bit skalaar Name[eu]=Ehundura 8k 32bit eskalarra +Name[fi]=Pintakuvio 8k 32 bit skalaarinen Name[fr]=Texture 8k 32bit scalaire Name[gl]=Textura de 8k e 32 bits escalar Name[hu]=Textúra 8k 32bit skalár Name[is]=Efnisáferð 8k 32bita scalar Name[it]=Trama 8k 32bit scalare Name[ja]=テクスチャ 8k 32 ビットスカラー Name[kk]=Текстура 8k 32 бит скаляр Name[nb]=Tekstur 8k 32bit skalar Name[nl]=Textuur 8k 32bit scalar Name[pl]=Tekstura 8k 32bit skalar Name[pt]=Textura 8k 32-bits escalar Name[pt_BR]=Textura 8k 32bits escalar Name[ru]=Текстура 8k 32 бит scalar Name[sk]=Textúra 8k 32bit skalár Name[sv]=Struktur 8k 32-bitar skalär Name[tr]=Doku 8k 32bit sayısal Name[uk]=Текстура 8k, 32-бітова, скалярна Name[x-test]=xxTexture 8k 32bit scalarxx Name[zh_CN]=8K 纹理模板 32 位 Scalar 色彩空间 Name[zh_TW]=紋理 8k 32位元 scalar Type=Link URL[$e]=.source/Texture8k32bitscalar.kra X-KDE-Hidden=false diff --git a/krita/data/templates/texture/Texture8k8bitsrgb.desktop b/krita/data/templates/texture/Texture8k8bitsrgb.desktop index f73fb9a830..a426f214ab 100755 --- a/krita/data/templates/texture/Texture8k8bitsrgb.desktop +++ b/krita/data/templates/texture/Texture8k8bitsrgb.desktop @@ -1,38 +1,39 @@ [Desktop Entry] Icon=template_texture Name=Texture 8k 8bit srgb Name[bs]=Tekstura 8k 8bit srgb Name[ca]=Textura 8k de 8 bits amb SRGB Name[ca@valencia]=Textura 8k de 8 bits amb SRGB Name[cs]=Textura 8k 8bit srgb Name[da]=Tekstur 8k 8bit srgb Name[de]=Textur 8k 8bit srgb Name[el]=Υφή 8k 8bit srgb Name[en_GB]=Texture 8k 8bit srgb Name[es]=Textura 8k 8bit srgb Name[et]=Tekstuur 8k 8bit srgb Name[eu]=Ehundura 8k 8bit sGBU +Name[fi]=Pintakuvio 8k 8 bit SRGB Name[fr]=Texture 8k 8bit srgb Name[gl]=Textura de 8k e 8 bits SRGB Name[hu]=Textúra 8k 8bit srgb Name[is]=Efnisáferð 8k 8bita srgb Name[it]=Trama 8k 8bit srgb Name[ja]=テクスチャ 8k 8 ビット sRGB Name[kk]=Текстура 8k 8 бит srgb Name[nb]=Tekstur 8k 8bit srgb Name[nl]=Textuur 8k 8bit srgb Name[pl]=Tekstura 8k 8bit srgb Name[pt]=Textura 8k 8-bits sRGB Name[pt_BR]=Textura 8k 8bits sRGB Name[ru]=Текстура 8k 8 бит srgb Name[sk]=Textúra 8k 8bit srgb Name[sl]=Tekstura 8k 8 bitov srgb Name[sv]=Struktur 8k 8-bitar SRGB Name[tr]=Doku 8k 8bit srgb Name[uk]=Текстура 8k, 8-бітова, srgb Name[x-test]=xxTexture 8k 8bit srgbxx Name[zh_CN]=8K 纹理模板 8 位 sRGB 色彩空间 Name[zh_TW]=紋理 8k 8位元 srgb Type=Link URL[$e]=.source/Texture8k8bitsrgb.kra X-KDE-Hidden=false diff --git a/krita/org.kde.krita.appdata.xml b/krita/org.kde.krita.appdata.xml index b92b2e66b0..2458eb80a9 100644 --- a/krita/org.kde.krita.appdata.xml +++ b/krita/org.kde.krita.appdata.xml @@ -1,259 +1,262 @@ org.kde.krita org.kde.krita.desktop CC0-1.0 GPL-3.0-only Krita Foundation Fundació Krita Fundació Krita Krita Foundation Krita Foundation Krita Foundation Fundación Krita Krita Fundazioa + Krita Foundation La Fondation Krita Fundación Krita Asas Krita Fondazione Krita Krita Foundation Fundacja Krity Fundação do Krita Krita Foundation Krita-stiftelsen Фундація Krita xxKrita Foundationxx Krita 基金会 Krita 基金會 foundation@krita.org Krita كريتا Krita Krita Krita Krita Krita Krita Krita Krita + Krita Krita Krita Krita Krita Krita Krita Krita Krita Krita Krita Krita Krita Krita xxKritaxx Krita Krita Digital Painting, Creative Freedom رسم رقميّ، حريّة إبداعيّة Digitalno crtanje, kreativna sloboda Dibuix digital, Llibertat creativa Dibuix digital, Llibertat creativa Digitální malování, svoboda tvorby Digital tegning, kunstnerisk frihed Digitales Malen, kreative Freiheit Ψηφιακή ζωγραφική, δημιουργική ελευθερία Digital Painting, Creative Freedom Pintura digital, libertad creativa Digitaalne joonistamine, loominguline vabadus Margolan digitala, sormen askatasuna Digitaalimaalaus, luova vapaus Peinture numérique, liberté créatrice Debuxo dixital, liberdade creativa Pictura digital, Libertate creative Pelukisan Digital, Kebebasan Berkreatif Pittura digitale, libertà creativa Digital Painting, Creative Freedom Cyfrowe malowanie, Wolność Twórcza Pintura Digital, Liberdade Criativa Pintura digital, liberdade criativa Цифровое рисование. Творческая свобода Digitálne maľovanie, kreatívna sloboda Digital målning, kreativ frihet Sayısal Boyama, Yaratıcı Özgürlük Цифрове малювання, творча свобода xxDigital Painting, Creative Freedomxx 自由挥洒数字绘画的无限创意 數位繪畫,創作自由

Krita is the full-featured digital art studio.

Krita je potpuni digitalni umjetnički studio.

Krita és l'estudi d'art digital ple de funcionalitats.

Krita és l'estudi d'art digital ple de funcionalitats.

Krita ist ein digitales Designstudio mit umfangreichen Funktionen.

Το Krita είναι ένα πλήρες χαρακτηριστικών ψηφιακό ατελιέ.

Krita is the full-featured digital art studio.

Krita es un estudio de arte digital completo

Krita on rohkete võimalustega digitaalkunstistuudio.

Krita arte lantegi digital osoa da.

Krita on täyspiirteinen digitaiteen ateljee.

Krita est le studio d'art numérique complet.

Krita é un estudio completo de arte dixital.

Krita es le studio de arte digital complete.

Krita adalah studio seni digital yang penuh dengan fitur.

Krita è uno studio d'arte digitale completo.

Krita は、フル機能を備えたデジタルなアートスタジオです。

Krita is de digitale kunststudio vol mogelijkheden.

Krita jest pełnowymiarowym, cyfrowym studiem artystycznym

O Krita é o estúdio de arte digital completo.

O Krita é o estúdio de arte digital completo.

Krita — полнофункциональный инструмент для создания цифровой графики.

Krita je plne vybavené digitálne umelecké štúdio.

Krita är den fullfjädrade digitala konststudion.

Krita, tam özellikli dijital sanat stüdyosudur.

Krita — повноцінний комплекс для створення цифрових художніх творів.

xxKrita is the full-featured digital art studio.xx

Krita 是一款功能齐全的数字绘画工作室软件。

Krita 是全功能的數位藝術工作室。

It is perfect for sketching and painting, and presents an end–to–end solution for creating digital painting files from scratch by masters.

On je savršen za skiciranje i slikanje i predstavlja finalno rješenje za kreiranje digitalnih slika od nule s majstorima

És perfecte per fer esbossos i pintar, i presenta una solució final per crear fitxers de dibuix digital des de zero per a mestres.

És perfecte per fer esbossos i pintar, i presenta una solució final per crear fitxers de dibuix digital des de zero per a mestres.

Είναι ιδανικό για σκιτσογραφία και ζωγραφική, και παρουσιάζει μια από άκρη σε άκρη λύση για τη δημιουργία από το μηδέν αρχείων ψηφιακης ζωγραφικής από τους δασκάλους της τέχνης.

It is perfect for sketching and painting, and presents an end–to–end solution for creating digital painting files from scratch by masters.

Es perfecto para diseñar y pintar, y ofrece una solución completa para crear desde cero archivos de pintura digital apta para profesionales.

See on suurepärane töövahend visandite ja joonistuste valmistamiseks ning annab andekatele kunstnikele võimaluse luua digitaalpilt algusest lõpuni just oma käe järgi.

Zirriborratzeko eta margotzeko ezin hobea da, eta margolan digitalen fitxategiak hutsetik sortzeko muturretik-muturrera konponbide bat aurkezten du, maisuentzako mailakoa.

Se on täydellinen luonnosteluun ja maalaukseen ja tarjoaa kokonaisratkaisun digitaalisten kuvatiedostojen luomiseen alusta alkaen.

Il est parfait pour crayonner et peindre, et constitue une solution de bout en bout pour créer des fichier de peinture numérique depuis la feuille blanche jusqu'au épreuves finales.

Resulta perfecto para debuxar e pintar, e presenta unha solución completa que permite aos mestres crear ficheiros de debuxo dixital desde cero.

Illo es perfecte pro schizzar e pinger, e presenta un solution ab fin al fin pro crear files de pictura digital ab grattamentos per maestros.

Ini adalah sempurna untuk mensketsa dan melukis, dan menghadirkan sebuah solusi untuk menciptakan file-file pelukisan digital dari goresan si pelukis ulung.

Perfetto per fare schizzi e dipingere, prevede una soluzione completa che consente agli artisti di creare file di dipinti digitali partendo da zero.

Het is perfect voor schetsen en schilderen en zet een end–to–end oplossing voor het maken van digitale bestanden voor schilderingen vanuit het niets door meesters.

Nadaje się perfekcyjnie do szkicowania i malowania i dostarcza zupełnego rozwiązania dla tworzenia plików malowideł cyfrowych od zalążka.

É perfeito para desenhos e pinturas, oferecendo uma solução final para criar ficheiros de pintura digital do zero por mestres.

É perfeito para desenhos e pinturas, oferecendo uma solução final para criar arquivos de desenho digital feitos a partir do zero por mestres.

Она превосходно подходит для набросков и рисования, предоставляя мастерам самодостаточный инструмент для создания цифровой живописи с нуля.

Je ideálna na skicovanie a maľovanie a poskytuje end-to-end riešenie na vytváranie súborov digitálneho maľovania od základu od profesionálov.

Den är perfekt för att skissa och måla, samt erbjuder en helomfattande lösning för att skapa digitala målningsfiler från grunden av mästare.

Eskiz ve boyama için mükemmeldir ve ustaların sıfırdan dijital boyama dosyaları oluşturmak için uçtan-uca bir çözüm sunar.

Цей комплекс чудово пасує для створення ескізів та художніх зображень і є самодостатнім набором для створення файлів цифрових полотен «з нуля» для справжніх художників.

xxIt is perfect for sketching and painting, and presents an end–to–end solution for creating digital painting files from scratch by masters.xx

它专门为数字绘画设计,为美术工作者提供了一个从起草、上色到完成作品等整个创作流程的完整解决方案。

它是素描和繪畫的完美選擇,並提供了一個從零開始建立數位繪畫檔的端到端解決方案。

Krita is a great choice for creating concept art, comics, textures for rendering and matte paintings. Krita supports many colorspaces like RGB and CMYK at 8 and 16 bits integer channels, as well as 16 and 32 bits floating point channels.

Krita je odličan izbor za kreiranje konceptualne umjetnosti, stripove, teksture za obradu i mat slike. Krita podržava mnoge prostore boja kao RGB i CMIK na 8 i 16 bitnim cjelobrojnim kanalimaa, kao i 16 i 32 bita floating point kanalima.

El Krita és una gran elecció per crear art conceptual, còmics, textures per renderitzar i pintures «matte». El Krita permet molts espais de color com el RGB i el CMYK a 8 i 16 bits de canals sencers, així com 16 i 32 bits de canals de coma flotant.

El Krita és una gran elecció per crear art conceptual, còmics, textures per renderitzar i pintures «matte». El Krita permet molts espais de color com el RGB i el CMYK a 8 i 16 bits de canals sencers, així com 16 i 32 bits de canals de coma flotant.

Το Krita είναι μια εξαιρετική επιλογή για τη δημιουργία αφηρημένης τέχνης, ιστοριών με εικόνες, υφής για ζωγραφική αποτύπωσης και διάχυσης φωτός. Το Krita υποστηρίζει πολλούς χρωματικούς χώρους όπως τα RGB και CMYK σε 8 και 16 bit κανάλια ακεραίων καθώς επίσης και σε 16 και 32 bit κανάλια κινητής υποδιαστολής,

Krita is a great choice for creating concept art, comics, textures for rendering and matte paintings. Krita supports many colourspaces like RGB and CMYK at 8 and 16 bits integer channels, as well as 16 and 32 bits floating point channels.

Krita es una gran elección para crear arte conceptual, cómics, texturas para renderizar y «matte paintings». Krita permite el uso de muchos espacios de color, como, por ejemplo, RGB y CMYK, tanto en canales de enteros de 8 y 16 bits, así como en canales de coma flotante de 16 y 32 bits.

Krita on üks paremaid valikuid kontseptuaalkunsti, koomiksite, tekstuuride ja digitaalmaalide loomiseks. Krita toetab paljusid värviruume, näiteks RGB ja CMYK 8 ja 16 täisarvulise bitiga kanali kohta, samuti 16 ja 32 ujukomabitiga kanali kohta.

Krita aukera bikaina da kontzeptuzko artea, komikiak, errendatzeko ehundurak eta «matte» margolanak sortzeko. Kritak kolore-espazio ugari onartzen ditu hala nola GBU eta CMYK, 8 eta 16 biteko osoko kanaletan, baita 16 eta 32 biteko koma-higikorreko kanaletan.

Krita on hyvä valinta konseptikuvituksen, sarjakuvien, pintakuvioiden ja maalausten luomiseen. Krita tukee useita väriavaruuksia kuten RGB:tä ja CMYK:ta 8 ja 16 bitin kokonaisluku- samoin kuin 16 ja 32 bitin liukulukukanavin.

Krita est un très bon choix pour créer des concepts arts, des bandes-dessinées, des textures de rendu et des peintures. Krita prend en charge plusieurs espaces de couleurs comme RVB et CMJN avec les canaux de 8 et 16 bits entiers ainsi que les canaux de 16 et 32 bits flottants.

Krita é unha gran opción para crear arte conceptual, texturas para renderización e pinturas mate. Krita permite usar moitos espazos de cores como RGB e CMYK con canles de 8 e 16 bits, así como canles de coma flotante de 16 e 32 bits.

Krita es un grande selection pro crear arte de concepto, comics, texturas pro rendering e picturas opac. Krita supporta multe spatios de colores como RGB e CMYK con canales de integer a 8 e 16 bits, como anque canales floating point a 16 e 32 bits.

Krita adalah pilihan yang cocok untuk menciptakan konsep seni, komik, tekstur untuk rendering dan lukisan matte. Krita mendukung banyak ruang warna seperti RGB dan CMYK pada channel integer 8 dan 16 bit, serta 16 dan 32 bit channel titik mengambang.

Krita rappresenta una scelta ottimale per la creazione di arte concettuale, fumetti e texture per il rendering e il matte painting. Krita supporta molti spazi colori come RGB e CMYK a 8 e 16 bit per canali interi e 16 e 32 bit per canali a virgola mobile.

コンセプトアート、コミック、3DCG 用テクスチャ、マットペイントを制作する方にとって、Krita は最適な選択です。Krita は、8/16 ビット整数/チャンネル、および 16/32 ビット浮動小数点/チャンネルの RGB や CMYK をはじめ、さまざまな色空間をサポートしています。

Krita is een goede keuze voor het maken van kunstconcepten, strips, textuur voor weergeven en matte schilderijen. Krita ondersteunt vele kleurruimten zoals RGB en CMYK in 8 en 16 bits kanalen met gehele getallen, evenals 16 en 32 bits kanalen met drijvende komma.

Krita jest świetnym wyborem przy tworzeniu koncepcyjnej sztuki, komiksów, tekstur do wyświetlania i kaszet. Krita obsługuje wiele przestrzeni barw takich jak RGB oraz CMYK dla kanałów 8 oraz 16 bitowych wyrażonych w l. całkowitych, a także 16 oraz 32 bitowych wyrażonych w l. zmiennoprzecinkowych.

O Krita é uma óptima escolha para criar arte conceptual, banda desenhada, texturas para desenho e pinturas. O Krita suporta diversos espaços de cores como o RGB e o CMYK com canais de cores inteiros a 8 e 16 bits, assim como canais de vírgula flutuante a 16 e a 32 bits.

O Krita é uma ótima escolha para criação de arte conceitual, histórias em quadrinhos, texturas para desenhos e pinturas. O Krita tem suporte a diversos espaços de cores como RGB e CMYK com canais de cores inteiros de 8 e 16 bits, assim como canais de ponto flutuante de 16 e 32 bits.

Krita — отличный выбор для создания концепт-артов, комиксов, текстур для рендеринга и рисования. Она поддерживает множество цветовых пространств включая RGB и CMYK с 8 и 16 целыми битами на канал, а также 16 и 32 битами с плавающей запятой на канал.

Krita je výborná voľba pre vytváranie konceptového umenia, textúr na renderovanie a matné kresby. Krita podporuje mnoho farebných priestorov ako RGB a CMYK na 8 a 16 bitových celočíselných kanáloch ako aj 16 a 32 bitových reálnych kanáloch.

Krita är ett utmärkt val för att skapa concept art, serier, strukturer för återgivning och bakgrundsmålningar. Krita stöder många färgrymder som RGB och CMYK med 8- och 16-bitars heltal, samt 16- och 32-bitars flyttal.

Krita, konsept sanat, çizgi roman, kaplama ve mat resimler için dokular oluşturmak için mükemmel bir seçimdir. Krita, 8 ve 16 bit tamsayı kanallarında RGB ve CMYK gibi birçok renk alanını ve 16 ve 32 bit kayan nokta kanallarını desteklemektedir.

Krita — чудовий інструмент для створення концептуального живопису, коміксів, текстур для моделей та декорацій. У Krita передбачено підтримку багатьох просторів кольорів, зокрема RGB та CMYK з 8-бітовими та 16-бітовими цілими значеннями, а також 16-бітовими та 32-бітовими значеннями з рухомою крапкою для каналів кольорів.

xxKrita is a great choice for creating concept art, comics, textures for rendering and matte paintings. Krita supports many colorspaces like RGB and CMYK at 8 and 16 bits integer channels, as well as 16 and 32 bits floating point channels.xx

Krita 是绘制概念美术、漫画、纹理和电影布景的理想选择。Krita 支持多种色彩空间,如 8 位和 16 位整数及 16 位和 32 位浮点的 RGB 和 CMYK 颜色模型。

Krita 是創造概念藝術、漫畫、彩現紋理和場景繪畫的絕佳選擇。Krita 在 8 位元和 16 位元整數色版,以及 16 位元和 32 位元浮點色版中支援 RGB 和 CMYK 等多種色彩空間。

Have fun painting with the advanced brush engines, amazing filters and many handy features that make Krita enormously productive.

Zabavite se kreirajući napredne pogone četki, filtere i mnoge praktične osobine koje čine Krita vrlo produktivnim.

Gaudiu pintant amb els motors de pinzells avançats, els filtres impressionants i moltes funcionalitats útils que fan el Krita molt productiu.

Gaudiu pintant amb els motors de pinzells avançats, els filtres impressionants i moltes funcionalitats útils que fan el Krita molt productiu.

Διασκεδάστε ζωγραφίζοντας με τις προηγμένες μηχανές πινέλων, με εκπληκτικά φίλτρα και πολλά εύκολης χρήσης χαρακτηριστικά που παρέχουν στο Krita εξαιρετικά αυξημένη παραγωγικότητα.

Have fun painting with the advanced brush engines, amazing filters and many handy features that make Krita enormously productive.

Diviértase pintando con los avanzados motores de pinceles, los espectaculares filtros y muchas funcionalidades prácticas que hacen que Krita sea enormemente productivo.

Joonistamise muudavad tunduvalt lõbusamaks võimsad pintslimootorid, imetabased filtrid ja veel paljud käepärased võimalused, mis muudavad Krita kasutaja tohutult tootlikuks.

Marrazten ondo pasa ezazu, isipu motor aurreratuekin, iragazki txundigarriekin eta eginbide praktiko ugariekin, zeintzuek Krita ikaragarri emankorra egiten duten.

Pidä hauskaa maalatessasi edistyneillä sivellinmoottoreilla, hämmästyttävillä suotimilla ja monilla muilla kätevillä ominaisuuksilla, jotka tekevät Kritasta tavattoman tehokkaan.

Amusez-vous à peindre avec les outils de brosse avancés, les filtres incroyables et les nombreuses fonctionnalités pratiques qui rendent Krita extrêmement productif.

Goza debuxando con motores de pincel avanzados, filtros fantásticos e moitas outras funcionalidades útiles que fan de Krita un programa extremadamente produtivo.

Amusa te a pinger con le motores de pincel avantiate, filtros stupende e multe characteristicas amical que face Krita enormemente productive.

Bersenang-senanglah melukis dengan mesin kuas canggih, filter luar biasa dan banyak fitur berguna yang membuat Krita sangat produktif.

Divertiti a dipingere con gli avanzati sistemi di pennelli, i sorprendenti filtri e molte altre utili caratteristiche che fanno di Krita un software enormemente produttivo.

Krita のソフトウェアとしての生産性を高めている先進的なブラシエンジンや素晴らしいフィルタのほか、便利な機能の数々をお楽しみください。

Veel plezier met schilderen met the geavanceerde penseel-engines, filters vol verbazing en vele handige mogelijkheden die maken dat Krita enorm productief is.

Baw się przy malowaniu przy użyciu zaawansowanych silników pędzli, zadziwiających filtrów i wielu innych przydatnych cech, które czynią z Krity bardzo produktywną.

Divirta-se a pintar com os motores de pincéis avançados, os filtros espantosos e muitas outras funcionalidades úteis que tornam o Krita altamente produtivo.

Divirta-se pintando com os mecanismos de pincéis avançados, filtros maravilhosos e muitas outras funcionalidades úteis que tornam o Krita altamente produtivo.

Получайте удовольствие от использования особых кистевых движков, впечатляющих фильтров и множества других функций, делающих Krita сверхпродуктивной.

Užívajte si maľovanie s pokročilými kresliacimi enginmi, úžasnými filtrami a mnohými užitočnými funkciami, ktoré robia Kritu veľmi produktívnu.

Ha det så kul vid målning med de avancerade penselfunktionerna, fantastiska filtren och många praktiska funktioner som gör Krita så enormt produktiv.

Gelişmiş fırça motorları, şaşırtıcı filtreler ve Krita'yı son derece üretken yapan bir çok kullanışlı özellikli boya ile iyi eğlenceler.

Отримуйте задоволення від малювання за допомогою пензлів з найширшими можливостями, чудових фільтрів та багатьох зручних можливостей, які роблять Krita надзвичайно продуктивним засобом малювання.

xxHave fun painting with the advanced brush engines, amazing filters and many handy features that make Krita enormously productive.xx

Krita 具有功能强大的笔刷引擎、种类繁多的滤镜以及便于操作的交互设计,可让你尽情、高效地挥洒无限创意。

使用先進的筆刷引擎、驚人的濾鏡和許多方便的功能來開心地繪畫,讓 Krita 擁有巨大的生產力。

https://www.krita.org/ https://krita.org/about/faq/ https://krita.org/support-us/donations/ https://docs.krita.org/Category:Tutorials https://cdn.kde.org/screenshots/krita/2018-03-17_screenshot_001.png https://cdn.kde.org/screenshots/krita/2018-03-17_screenshot_002.png https://cdn.kde.org/screenshots/krita/2018-03-17_screenshot_003.png https://cdn.kde.org/screenshots/krita/2018-03-17_screenshot_004.png https://cdn.kde.org/screenshots/krita/2018-03-17_screenshot_005.png https://cdn.kde.org/screenshots/krita/2018-03-17_screenshot_006.png none none none none none none none none none none none none none none none none none none none none Graphics KDE krita + org.kde.krita.desktop
diff --git a/libs/brush/kis_brush.h b/libs/brush/kis_brush.h index 4a562bd799..3ccb6c62f3 100644 --- a/libs/brush/kis_brush.h +++ b/libs/brush/kis_brush.h @@ -1,397 +1,397 @@ /* * Copyright (c) 1999 Matthias Elter * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_BRUSH_ #define KIS_BRUSH_ #include #include #include #include #include #include class KisQImagemask; typedef KisSharedPtr KisQImagemaskSP; class QString; class KoColor; class KoColorSpace; class KisPaintInformation; class KisBoundary; class KisPaintopLodLimitations; enum enumBrushType { INVALID, MASK, IMAGE, PIPE_MASK, PIPE_IMAGE }; static const qreal DEFAULT_SOFTNESS_FACTOR = 1.0; class KisBrush; typedef QSharedPointer KisBrushSP; /** * KisBrush is the base class for brush resources. A brush resource * defines one or more images that are used to potato-stamp along * the drawn path. The brush type defines how this brush is used -- * the important difference is between masks (which take the current * painting color) and images (which do not). It is up to the paintop * to make use of this feature. * * Brushes must be serializable to an xml representation and provide * a factory class that can recreate or retrieve the brush based on * this representation. * * XXX: This api is still a big mess -- it needs a good refactoring. * And the whole KoResource architecture is way over-designed. */ class BRUSH_EXPORT KisBrush : public KoResource, public KisShared { public: class ColoringInformation { public: virtual ~ColoringInformation(); virtual const quint8* color() const = 0; virtual void nextColumn() = 0; virtual void nextRow() = 0; }; protected: class PlainColoringInformation : public ColoringInformation { public: PlainColoringInformation(const quint8* color); ~PlainColoringInformation() override; const quint8* color() const override ; void nextColumn() override; void nextRow() override; private: const quint8* m_color; }; class PaintDeviceColoringInformation : public ColoringInformation { public: PaintDeviceColoringInformation(const KisPaintDeviceSP source, int width); ~PaintDeviceColoringInformation() override; const quint8* color() const override ; void nextColumn() override; void nextRow() override; private: const KisPaintDeviceSP m_source; KisHLineConstIteratorSP m_iterator; }; public: KisBrush(); KisBrush(const QString& filename); ~KisBrush() override; virtual qreal userEffectiveSize() const = 0; virtual void setUserEffectiveSize(qreal value) = 0; bool load() override { return false; } bool loadFromDevice(QIODevice *) override { return false; } bool save() override { return false; } bool saveToDevice(QIODevice* ) const override { return false; } /** * @brief brushImage the image the brush tip can paint with. Not all brush types have a single * image. * @return a valid QImage. */ virtual QImage brushTipImage() const; /** * Change the spacing of the brush. * @param spacing a spacing of 1.0 means that strokes will be separated from one time the size * of the brush. */ virtual void setSpacing(double spacing); /** * @return the spacing between two strokes for this brush */ double spacing() const; void setAutoSpacing(bool active, qreal coeff); bool autoSpacingActive() const; qreal autoSpacingCoeff() const; /** * @return the width (for scale == 1.0) */ qint32 width() const; /** * @return the height (for scale == 1.0) */ qint32 height() const; /** * @return the width of the mask for the given scale and angle */ virtual qint32 maskWidth(KisDabShape const&, qreal subPixelX, qreal subPixelY, const KisPaintInformation& info) const; /** * @return the height of the mask for the given scale and angle */ virtual qint32 maskHeight(KisDabShape const&, qreal subPixelX, qreal subPixelY, const KisPaintInformation& info) const; /** * @return the logical size of the brush, that is the size measured * in floating point value. * * This value should not be used for calculating future dab sizes * because it doesn't take any rounding into account. The only use * of this metric is calculation of brush-size derivatives like * hotspots and spacing. */ virtual QSizeF characteristicSize(KisDabShape const&) const; /** * @return the angle of the mask adding the given angle */ double maskAngle(double angle = 0) const; /** * @return the index of the brush * if the brush consists of multiple images */ virtual quint32 brushIndex(const KisPaintInformation& info) const; /** * The brush type defines how the brush is used. */ virtual enumBrushType brushType() const; QPointF hotSpot(KisDabShape const&, const KisPaintInformation& info) const; /** * Returns true if this brush can return something useful for the info. This is used * by Pipe Brushes that can't paint sometimes **/ virtual bool canPaintFor(const KisPaintInformation& /*info*/); /** * Is called by the paint op when a paintop starts a stroke. The * point is that we store brushes a server while the paint ops are * are recreated all the time. Is means that upon a stroke start * the brushes may need to clear its state. */ virtual void notifyStrokeStarted(); /** * Is called by the cache, when cache hit has happened. * Having got this notification the brush can update the counters * of dabs, generate some new random values if needed. * * * NOTE: one should use **either** notifyCachedDabPainted() or prepareForSeqNo() * * Currently, this is used by pipe'd brushes to implement * incremental and random parasites */ virtual void notifyCachedDabPainted(const KisPaintInformation& info); /** * Is called by the multithreaded queue to prepare a specific brush * tip for the particular seqNo. * * NOTE: one should use **either** notifyCachedDabPainted() or prepareForSeqNo() * * Currently, this is used by pipe'd brushes to implement * incremental and random parasites */ virtual void prepareForSeqNo(const KisPaintInformation& info, int seqNo); /** * Notify the brush if it can use QtConcurrent's threading capabilities in its * internal routines. By default it is allowed, but some paintops (who do their * own multithreading) may ask the brush to avoid internal threading. */ void setThreadingAllowed(bool value); /** * \see setThreadingAllowed() for details */ bool threadingAllowed() const; /** * Return a fixed paint device that contains a correctly scaled image dab. */ virtual KisFixedPaintDeviceSP paintDevice(const KoColorSpace * colorSpace, KisDabShape const&, const KisPaintInformation& info, double subPixelX = 0, double subPixelY = 0) const; /** * clear dst fill it with a mask colored with KoColor */ void mask(KisFixedPaintDeviceSP dst, const KoColor& color, KisDabShape const& shape, const KisPaintInformation& info, double subPixelX = 0, double subPixelY = 0, qreal softnessFactor = DEFAULT_SOFTNESS_FACTOR) const; /** * clear dst and fill it with a mask colored with the corresponding colors of src */ void mask(KisFixedPaintDeviceSP dst, const KisPaintDeviceSP src, KisDabShape const& shape, const KisPaintInformation& info, double subPixelX = 0, double subPixelY = 0, qreal softnessFactor = DEFAULT_SOFTNESS_FACTOR) const; virtual bool hasColor() const; /** * Create a mask and either mask dst (that is, change all alpha values of the * existing pixels to those of the mask) or, if coloringInfo is present, clear * dst and fill dst with pixels according to coloringInfo, masked according to the * generated mask. * * @param dst the destination that will be draw on the image, and this function * will edit its alpha channel * @param coloringInfo coloring information that will be copied on the dab, it can be null - * @param scale a scale applied on the alpha mask - * @param angle a rotation applied on the alpha mask + * @param shape a shape applied on the alpha mask * @param info the painting information (this is only and should only be used by * KisImagePipeBrush and only to be backward compatible with the Gimp, * KisImagePipeBrush is ignoring scale and angle information) * @param subPixelX sub position of the brush (contained between 0.0 and 1.0) * @param subPixelY sub position of the brush (contained between 0.0 and 1.0) + * @param softnessFactor softness factor of the brush * * @return a mask computed from the grey-level values of the * pixels in the brush. */ virtual void generateMaskAndApplyMaskOrCreateDab(KisFixedPaintDeviceSP dst, ColoringInformation* coloringInfo, KisDabShape const&, const KisPaintInformation& info, double subPixelX = 0, double subPixelY = 0, qreal softnessFactor = DEFAULT_SOFTNESS_FACTOR) const; /** * Serialize this brush to XML. */ virtual void toXML(QDomDocument& , QDomElement&) const; static KisBrushSP fromXML(const QDomElement& element); virtual const KisBoundary* boundary() const; virtual QPainterPath outline() const; virtual void setScale(qreal _scale); qreal scale() const; virtual void setAngle(qreal _angle); qreal angle() const; void clearBrushPyramid(); virtual void lodLimitations(KisPaintopLodLimitations *l) const; virtual KisBrushSP clone() const = 0; protected: KisBrush(const KisBrush& rhs); void setWidth(qint32 width); void setHeight(qint32 height); void setHotSpot(QPointF); /** * XXX */ virtual void setBrushType(enumBrushType type); virtual void setHasColor(bool hasColor); public: /** * The image is used to represent the brush in the gui, and may also, depending on the brush type * be used to define the actual brush instance. */ virtual void setBrushTipImage(const QImage& image); /** * Returns true if the brush has a bunch of pixels almost * fully transparent in the very center. If the brush is pierced, * then dulling mode may not work correctly due to empty samples. * * WARNING: this method is relatively expensive since it iterates * up to 100 pixels of the brush. */ bool isPiercedApprox() const; protected: void resetBoundary(); void predefinedBrushToXML(const QString &type, QDomElement& e) const; private: // Initialize our boundary void generateBoundary() const; struct Private; Private* const d; }; #endif // KIS_BRUSH_ diff --git a/libs/flake/KoCanvasControllerWidget.h b/libs/flake/KoCanvasControllerWidget.h index 37777b6c6f..f134fed94c 100644 --- a/libs/flake/KoCanvasControllerWidget.h +++ b/libs/flake/KoCanvasControllerWidget.h @@ -1,191 +1,193 @@ /* This file is part of the KDE project * Copyright (C) 2006, 2008 Thomas Zander * Copyright (C) 2007-2010 Boudewijn Rempt * Copyright (C) 2007-2008 C. Boemann * Copyright (C) 2006-2007 Jan Hambrecht * Copyright (C) 2009 Thorsten Zachmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOCANVASCONTROLLERWIDGET_H #define KOCANVASCONTROLLERWIDGET_H #include "kritaflake_export.h" #include #include #include "KoCanvasController.h" class KoShape; class KoCanvasBase; /** * KoCanvasController implementation for QWidget based canvases */ class KRITAFLAKE_EXPORT KoCanvasControllerWidget : public QAbstractScrollArea, public KoCanvasController { Q_OBJECT public: /** * Constructor. + * @param actionCollection the action collection for this widget * @param parent the parent this widget will belong to */ explicit KoCanvasControllerWidget(KActionCollection * actionCollection, QWidget *parent = 0); ~KoCanvasControllerWidget() override; /** * Reimplemented from QAbstractScrollArea. */ void scrollContentsBy(int dx, int dy) override; QSize viewportSize() const override; /// Reimplemented from KoCanvasController /** * Activate this canvascontroller */ virtual void activate(); void setCanvas(KoCanvasBase *canvas) override; KoCanvasBase *canvas() const override; /** * Change the actual canvas widget used by the current canvas. This allows the canvas widget * to be changed while keeping the current KoCanvasBase canvas and its associated resources as * they are. This might be used, for example, to switch from a QWidget to a QOpenGLWidget canvas. * @param widget the new canvas widget. */ virtual void changeCanvasWidget(QWidget *widget); int visibleHeight() const override; int visibleWidth() const override; int canvasOffsetX() const override; int canvasOffsetY() const override; void ensureVisible(const QRectF &rect, bool smooth = false) override; void ensureVisible(KoShape *shape) override; /** * will cause the toolOptionWidgetsChanged to be emitted and all * listeners to be updated to the new widget. * * FIXME: This doesn't belong her and it does an * inherits("KoView") so it too much tied to komain * * @param widgets the map of widgets */ void setToolOptionWidgets(const QList > &widgets); void zoomIn(const QPoint ¢er) override; void zoomOut(const QPoint ¢er) override; void zoomBy(const QPoint ¢er, qreal zoom) override; void zoomTo(const QRect &rect) override; /** * Zoom document keeping point \p widgetPoint unchanged * \param widgetPoint sticky point in widget pixels + * \param zoomCoeff the zoom */ virtual void zoomRelativeToPoint(const QPoint &widgetPoint, qreal zoomCoeff); void recenterPreferred() override; void setPreferredCenter(const QPointF &viewPoint) override; /// Returns the currently set preferred center point in view coordinates (pixels) QPointF preferredCenter() const override; void pan(const QPoint &distance) override; virtual void panUp() override; virtual void panDown() override; virtual void panLeft() override; virtual void panRight() override; void setMargin(int margin) override; QPoint scrollBarValue() const override; /** * Used by KisCanvasController to correct the scrollbars position * after the rotation. */ void setScrollBarValue(const QPoint &value) override; void updateDocumentSize(const QSize &sz, bool recalculateCenter = true) override; /** * Set mouse wheel to zoom behaviour * @param zoom if true wheel will zoom instead of scroll, control modifier will scroll */ void setZoomWithWheel(bool zoom) override; void setVastScrolling(qreal factor) override; QPointF currentCursorPosition() const override; void resetScrollBars() override; /** * \internal */ class Private; KoCanvasControllerWidget::Private *priv(); private Q_SLOTS: /// Called by the horizontal scrollbar when its value changes void updateCanvasOffsetX(); /// Called by the vertical scrollbar when its value changes void updateCanvasOffsetY(); protected: friend class KisZoomAndPanTest; qreal vastScrollingFactor() const; /// reimplemented from QWidget void paintEvent(QPaintEvent *event) override; /// reimplemented from QWidget void resizeEvent(QResizeEvent *resizeEvent) override; /// reimplemented from QWidget void dragEnterEvent(QDragEnterEvent *event) override; /// reimplemented from QWidget void dropEvent(QDropEvent *event) override; /// reimplemented from QWidget void dragMoveEvent(QDragMoveEvent *event) override; /// reimplemented from QWidget void dragLeaveEvent(QDragLeaveEvent *event) override; /// reimplemented from QWidget void wheelEvent(QWheelEvent *event) override; /// reimplemented from QWidget bool focusNextPrevChild(bool next) override; private: Q_PRIVATE_SLOT(d, void activate()) Private * const d; }; #endif diff --git a/libs/flake/KoFilterEffectRegistry.h b/libs/flake/KoFilterEffectRegistry.h index 594d3d2116..f2f0da880e 100644 --- a/libs/flake/KoFilterEffectRegistry.h +++ b/libs/flake/KoFilterEffectRegistry.h @@ -1,61 +1,62 @@ /* This file is part of the KDE project * Copyright (c) 2009 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOFILTEREFFECTREGISTRY_H #define KOFILTEREFFECTREGISTRY_H #include #include #include "kritaflake_export.h" #include class KoFilterEffectLoadingContext; class KoFilterEffect; class KRITAFLAKE_EXPORT KoFilterEffectRegistry : public KoGenericRegistry { public: KoFilterEffectRegistry(); ~KoFilterEffectRegistry() override; /** * Return the only instance of KoFilterEffectRegistry. * Creates an instance on the first call. */ static KoFilterEffectRegistry *instance(); /** * Creates filter effect from given xml element. - * @param element the xml element to load form + * @param element the xml element to load from + * @param context the loading context * @return the created filter effect if successful, otherwise returns 0 */ KoFilterEffect *createFilterEffectFromXml(const KoXmlElement &element, const KoFilterEffectLoadingContext &context); private: KoFilterEffectRegistry(const KoFilterEffectRegistry&); KoFilterEffectRegistry operator=(const KoFilterEffectRegistry&); void init(); class Private; Private * const d; }; #endif // KOFILTEREFFECTREGISTRY_H diff --git a/libs/flake/KoParameterShape.h b/libs/flake/KoParameterShape.h index ec308f1b81..f20502f9fb 100644 --- a/libs/flake/KoParameterShape.h +++ b/libs/flake/KoParameterShape.h @@ -1,165 +1,162 @@ /* This file is part of the KDE project Copyright (C) 2006 Thorsten Zachmann Copyright (C) 2007 Thomas Zander This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOPARAMETERSHAPE_H #define KOPARAMETERSHAPE_H #include "KoPathShape.h" #include "kritaflake_export.h" class KoParameterShapePrivate; class KisHandlePainterHelper; /** * KoParameterShape is the base class for all parametric shapes * in flake. * Parametric shapes are those whose appearance can be completely * defined by a few numerical parameters. Rectangle, ellipse and star * are examples of parametric shapes. * In flake, these shape parameters can be manipulated visually by means * of control points. These control points can be moved with the mouse * on the canvas which changes the shapes parameter values and hence the * shapes appearance in realtime. * KoParameterShape is derived from the KoPathShape class that means * by changing the shape parameters, the underlying path is manipulated. * A parametric shape can be converted into a path shape by simply calling * the setModified method. This makes the path tool know that it can handle * the shape like a path shape, so that modifying the single path points * is possible. */ class KRITAFLAKE_EXPORT KoParameterShape : public KoPathShape { public: KoParameterShape(); ~KoParameterShape() override; /** * @brief Move handle to point * * This method calls moveHandleAction. Overload moveHandleAction to get the behaviour you want. * After that updatePath and a repaint is called. * * @param handleId the id of the handle to move * @param point the point to move the handle to in document coordinates * @param modifiers the keyboard modifiers used during moving the handle */ void moveHandle(int handleId, const QPointF &point, Qt::KeyboardModifiers modifiers = Qt::NoModifier); /** * @brief Get the id of the handle within the given rect * * @param rect the rect in shape coordinates * @return id of the found handle or -1 if none was found */ int handleIdAt(const QRectF &rect) const; /** * @brief Get the handle position * * @param handleId the id of the handle for which to get the position in shape coordinates */ QPointF handlePosition(int handleId) const; /** * @brief Paint the handles * - * @param painter the painter to paint the handles on - * @param converter the view converter for applying the actual zoom - * @param handleRadius the radius of the handles used for painting + * @param handlesHelper the helper of the handles used for painting + * @sa KisHandlePainterHelper */ void paintHandles(KisHandlePainterHelper &handlesHelper); /** * @brief Paint the given handles * - * @param painter the painter to paint the handles on - * @param converter the view converter for applying the actual zoom + * @param handlesHelper the helper of the handle used for painting * @param handleId of the handle which should be repainted - * @param handleRadius the radius of the handle used for painting */ void paintHandle(KisHandlePainterHelper &handlesHelper, int handleId); /// reimplemented from KoShape void setSize(const QSizeF &size) override; /** * @brief Check if object is a parametric shape * * It is no longer a parametric shape when the path was manipulated * * @return true if it is a parametic shape, false otherwise */ bool isParametricShape() const; /** * @brief Set if the shape can be modified using parameters * * After the state is set to false it is no longer possible to work * with parameters on this shape. * * @param parametric the new state * @see isParametricShape */ void setParametricShape(bool parametric); QPointF normalize() override; /// return the number of handles set on the shape int handleCount() const; protected: /** * Get the handle positions for manipulating the parameters. * @see setHandles, handleCount() */ QList handles() const; /** * Set the new handle positions which are used by the user to manipulate the parameters. * @see handles(), handleCount() */ void setHandles(const QList &handles); /// constructor KoParameterShape(KoParameterShapePrivate *); /** * @brief Updates the internal state of a KoParameterShape. * * This method is called from moveHandle. * * @param handleId of the handle * @param point to move the handle to in shape coordinates * @param modifiers used during move to point */ virtual void moveHandleAction(int handleId, const QPointF & point, Qt::KeyboardModifiers modifiers = Qt::NoModifier) = 0; /** * @brief Update the path of the parameter shape * * @param size of the shape */ virtual void updatePath(const QSizeF &size) = 0; protected: Q_DECLARE_PRIVATE(KoParameterShape) }; #endif /* KOPARAMETERSHAPE_H */ diff --git a/libs/flake/KoPathShape.h b/libs/flake/KoPathShape.h index 6a788ae89b..8a79086661 100644 --- a/libs/flake/KoPathShape.h +++ b/libs/flake/KoPathShape.h @@ -1,522 +1,523 @@ /* This file is part of the KDE project Copyright (C) 2006, 2011 Thorsten Zachmann Copyright (C) 2007,2009 Thomas Zander Copyright (C) 2006-2008 Jan Hambrecht Copyright (C) 2011 Jean-Nicolas Artaud This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOPATHSHAPE_H #define KOPATHSHAPE_H #include "kritaflake_export.h" #include #include #include "KoTosContainer.h" #define KoPathShapeId "KoPathShape" class KoPathSegment; class KoPathPoint; class KoPathShapePrivate; class KoMarker; class KisHandlePainterHelper; typedef QPair KoPathPointIndex; /// a KoSubpath contains a path from a moveTo until a close or a new moveTo typedef QList KoSubpath; typedef QList KoSubpathList; /// The position of a path point within a path shape /** * @brief This is the base for all graphical objects. * * All graphical objects are based on this object e.g. lines, rectangulars, pies * and so on. * * The KoPathShape uses KoPathPoint's to describe the path of the shape. * * Here a short example: * 3 points connected by a curveTo's described by the following svg: * M 100,200 C 100,100 250,100 250,200 C 250,200 400,300 400,200. * * This will be stored in 3 KoPathPoint's as * The first point contains in * point 100,200 * controlPoint2 100,100 * The second point contains in * point 250,200 * controlPoint1 250,100 * controlPoint2 250,300 * The third point contains in * point 400,300 * controlPoint1 400,200 * * Not the segments are stored but the points. Out of the points the segments are * generated. See the outline method. The reason for storing it like that is that * it is the points that are modified by the user and not the segments. */ class KRITAFLAKE_EXPORT KoPathShape : public KoTosContainer { public: /** * @brief constructor */ KoPathShape(); /** * @brief */ ~KoPathShape() override; KoShape *cloneShape() const override; /// reimplemented void paint(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintContext) override; virtual void paintPoints(KisHandlePainterHelper &handlesHelper); /// reimplemented QRectF outlineRect() const override; /// reimplemented QPainterPath outline() const override; /// reimplemented QRectF boundingRect() const override; /// reimplemented QSizeF size() const override; QPainterPath pathStroke(const QPen &pen) const; /** * Resize the shape * * This makes sure that the pathshape will not be resized to 0 if the new size * is null as that makes it impossible to undo the change. * * All functions that overwrite this function should also use the resizeMatrix * function to get and use the same data in resizing. * * @see resizeMatrix() */ void setSize(const QSizeF &size) override; /// reimplemented bool hitTest(const QPointF &position) const override; // reimplemented void saveOdf(KoShapeSavingContext &context) const override; // reimplemented bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override; // basically the same as loadOdf but adapted to the contour cases // tag needs to be either contour-polygon or contour-path from another shape bool loadContourOdf(const KoXmlElement & element, KoShapeLoadingContext &context, const QSizeF &scaleFactor); /** basically the equivalent saveOdf but adapted to the contour cases + * @param context the saving context * @param originalSize the original size of the unscaled image. */ void saveContourOdf(KoShapeSavingContext &context, const QSizeF &originalSize) const; /// Removes all subpaths and their points from the path void clear(); /** * @brief Starts a new Subpath * * Moves the pen to p and starts a new subpath. * * @return the newly created point */ KoPathPoint *moveTo(const QPointF &p); /** * @brief Adds a new line segment * * Adds a straight line between the last point and the given point p. * * @return the newly created point */ KoPathPoint *lineTo(const QPointF &p); /** * @brief Adds a new cubic Bezier curve segment. * * Adds a cubic Bezier curve between the last point and the given point p, * using the control points specified by c1 and c2. * * @param c1 control point1 * @param c2 control point2 * @param p the endpoint of this curve segment * * @return The newly created point */ KoPathPoint *curveTo(const QPointF &c1, const QPointF &c2, const QPointF &p); /** * @brief Adds a new quadratic Bezier curve segment. * * Adds a quadratic Bezier curve between the last point and the given point p, * using the control point specified by c. * * @param c control point * @param p the endpoint of this curve segment * * @return The newly created point */ KoPathPoint *curveTo(const QPointF &c, const QPointF &p); /** * @brief Add an arc. * * Adds an arc starting at the current point. The arc will be converted to bezier curves. * * @param rx x radius of the ellipse * @param ry y radius of the ellipse * @param startAngle the angle where the arc will be started * @param sweepAngle the length of the angle * TODO add param to have angle of the ellipse * * @return The newly created point */ KoPathPoint *arcTo(qreal rx, qreal ry, qreal startAngle, qreal sweepAngle); /** * @brief Closes the current subpath */ void close(); /** * @brief Closes the current subpath * * It tries to merge the last and first point of the subpath * to one point and then closes the subpath. If merging is not * possible as the two point are to far from each other a close * will be done. * TODO define a maximum distance between the two points until this is working */ void closeMerge(); /** * @brief Normalizes the path data. * * The path points are transformed so that the top-left corner * of the bounding rect is at (0,0). * This should be called after adding points to the path or changing * positions of path points. * @return the offset by which the points are moved in shape coordinates. */ virtual QPointF normalize(); /** * @brief Returns the path points within the given rectangle. * @param rect the rectangle the requested points are in * @return list of points within the rectangle */ QList pointsAt(const QRectF &rect) const; /** * @brief Returns the list of path segments within the given rectangle. * @param rect the rectangle the requested segments are in * @return list of segments within the rectangle */ QList segmentsAt(const QRectF &rect) const; /** * @brief Returns the path point index of a given path point * * @param point the point for which you want to get the index * @return path point index of the point if it exists * otherwise KoPathPointIndex( -1, -1 ) */ KoPathPointIndex pathPointIndex(const KoPathPoint *point) const; /** * @brief Returns the path point specified by a path point index * * @param pointIndex index of the point to get * * @return KoPathPoint on success, 0 otherwise e.g. out of bounds */ KoPathPoint *pointByIndex(const KoPathPointIndex &pointIndex) const; /** * @brief Returns the segment specified by a path point index * * A segment is defined by the point index of the first point in the segment. * A segment contains the defined point and its following point. If the subpath is * closed and the and the pointIndex point to the last point in the subpath, the * following point is the first point in the subpath. * * @param pointIndex index of the first point of the segment * * @return Segment containing both points of the segment or KoPathSegment( 0, 0 ) on error e.g. out of bounds */ KoPathSegment segmentByIndex(const KoPathPointIndex &pointIndex) const; /** * @brief Returns the number of points in the path * * @return The number of points in the path */ int pointCount() const; /** * @brief Returns the number of subpaths in the path * * @return The number of subpaths in the path */ int subpathCount() const; /** * @brief Returns the number of points in a subpath * * @return The number of points in the subpath or -1 if subpath out of bounds */ int subpathPointCount(int subpathIndex) const; /** * @brief Checks if a subpath is closed * * @param subpathIndex index of the subpath to check * * @return true when the subpath is closed, false otherwise */ bool isClosedSubpath(int subpathIndex) const; /** * @brief Inserts a new point into the given subpath at the specified position * * This method keeps the subpath closed if it is closed, and open when it was * open. So it can change the properties of the point inserted. * You might need to update the point before/after to get the desired result * e.g. when you insert the point into a curve. * * @param point to insert * @param pointIndex index at which the point should be inserted * * @return true on success, * false when pointIndex is out of bounds */ bool insertPoint(KoPathPoint *point, const KoPathPointIndex &pointIndex); /** * @brief Removes a point from the path. * * Note that the ownership of the point will pass to the caller. * * @param pointIndex index of the point which should be removed * * @return The removed point on success, * otherwise 0 */ KoPathPoint *removePoint(const KoPathPointIndex &pointIndex); /** * @brief Breaks the path after the point index * * The new subpath will be behind the one that was broken. The segment between * the given point and the one behind will be removed. If you want to split at * one point insert first a copy of the point behind it. * This does not work when the subpath is closed. Use openSubpath for this. * It does not break at the last position of a subpath or if there is only one * point in the subpath. * * @param pointIndex index of the point after which the path should be broken * * @return true if the subpath was broken, otherwise false */ bool breakAfter(const KoPathPointIndex &pointIndex); /** * @brief Joins the given subpath with the following one * * Joins the given subpath with the following one by inserting a segment between * the two subpaths. * This does nothing if the specified subpath is the last subpath * or one of both subpaths is closed. * * @param subpathIndex index of the subpath being joined with the following subpath * * @return true if the subpath was joined, otherwise false */ bool join(int subpathIndex); /** * @brief Moves the position of a subpath within a path * * @param oldSubpathIndex old index of the subpath * @param newSubpathIndex new index of the subpath * * @return true if the subpath was moved, otherwise false e.g. if an index is out of bounds */ bool moveSubpath(int oldSubpathIndex, int newSubpathIndex); /** * @brief Opens a closed subpath * * The subpath is opened by removing the segment before the given point, making * the given point the new start point of the subpath. * * @param pointIndex the index of the point at which to open the closed subpath * @return the new position of the old first point in the subpath * otherwise KoPathPointIndex( -1, -1 ) */ KoPathPointIndex openSubpath(const KoPathPointIndex &pointIndex); /** * @brief Close a open subpath * * The subpath is closed be inserting a segment between the start and end point, making * the given point the new start point of the subpath. * * @return the new position of the old first point in the subpath * otherwise KoPathPointIndex( -1, -1 ) */ KoPathPointIndex closeSubpath(const KoPathPointIndex &pointIndex); /** * @brief Reverse subpath * * The last point becomes the first point and the first one becomes the last one. * * @param subpathIndex the index of the subpath to reverse */ bool reverseSubpath(int subpathIndex); /** * @brief Removes subpath from the path * @param subpathIndex the index of the subpath to remove * @return the removed subpath on success, 0 otherwise. */ KoSubpath *removeSubpath(int subpathIndex); /** * @brief Adds a subpath at the given index to the path * @param subpath the subpath to add * @param subpathIndex the index at which the new subpath should be inserted * @return true on success, false otherwise e.g. subpathIndex out of bounds */ bool addSubpath(KoSubpath *subpath, int subpathIndex); /** * @brief Combines two path shapes by appending the data of the specified path. * @param path the path to combine with * @return index of the first segment inserted or -1 on failure */ int combine(KoPathShape *path); /** * @brief Creates separate path shapes, one for each existing subpath. * @param separatedPaths the list which contains the separated path shapes * @return true if separating the path was successful, false otherwise */ bool separate(QList &separatedPaths); /** * Returns the specific path shape id. * * Path shape derived shapes have a different shape id which link them * to their respective shape factories. In most cases they do not have * a special tool for editing them. * This function returns the specific shape id for finding the shape * factory from KoShapeRegistry. The default KoPathShapeId is returned * from KoShape::shapeId() so that the generic path editing tool gets * activated when the shape is selected. * * @return the specific shape id */ virtual QString pathShapeId() const; /// Returns a odf/svg string representation of the path data with the given matrix applied. QString toString(const QTransform &matrix = QTransform()) const; /// Returns the fill rule for the path object Qt::FillRule fillRule() const; /// Sets the fill rule to be used for painting the background void setFillRule(Qt::FillRule fillRule); /// Creates path shape from given QPainterPath static KoPathShape *createShapeFromPainterPath(const QPainterPath &path); /// Returns the viewbox from the given xml element. static QRect loadOdfViewbox(const KoXmlElement &element); void setMarker(KoMarker *marker, KoFlake::MarkerPosition pos); KoMarker* marker(KoFlake::MarkerPosition pos) const; bool hasMarkers() const; bool autoFillMarkers() const; void setAutoFillMarkers(bool value); public: struct KRITAFLAKE_EXPORT PointSelectionChangeListener : public ShapeChangeListener { void notifyShapeChanged(ChangeType type, KoShape *shape) override; virtual void recommendPointSelectionChange(KoPathShape *shape, const QList &newSelection) = 0; virtual void notifyPathPointsChanged(KoPathShape *shape) = 0; }; void recommendPointSelectionChange(const QList &newSelection); protected: void notifyPointsChanged(); private: /// constructor: to be used in cloneShape(), not in descendants! /// \internal KoPathShape(const KoPathShape &rhs); protected: /// constructor:to be used in descendant shapes /// \internal KoPathShape(KoPathShapePrivate *); /// reimplemented QString saveStyle(KoGenStyle &style, KoShapeSavingContext &context) const override; /// reimplemented void loadStyle(const KoXmlElement &element, KoShapeLoadingContext &context) override; /** * @brief Add an arc. * * Adds an arc starting at the current point. The arc will be converted to bezier curves. * @param rx x radius of the ellipse * @param ry y radius of the ellipse * @param startAngle the angle where the arc will be started * @param sweepAngle the length of the angle * TODO add param to have angle of the ellipse * @param offset to the first point in the arc * @param curvePoints a array which take the curve points, pass a 'QPointF curvePoins[12]'; * * @return number of points created by the curve */ int arcToCurve(qreal rx, qreal ry, qreal startAngle, qreal sweepAngle, const QPointF &offset, QPointF *curvePoints) const; /** * Get the resize matrix * * This makes sure that also if the newSize isNull that there will be a * very small size of 0.000001 pixels */ QTransform resizeMatrix( const QSizeF &newSize ) const; private: Q_DECLARE_PRIVATE(KoPathShape) }; Q_DECLARE_METATYPE(KoPathShape*) #endif /* KOPATHSHAPE_H */ diff --git a/libs/flake/KoResourceManager_p.h b/libs/flake/KoResourceManager_p.h index af17591a57..e4d2140baa 100644 --- a/libs/flake/KoResourceManager_p.h +++ b/libs/flake/KoResourceManager_p.h @@ -1,220 +1,220 @@ /* Copyright (c) 2006, 2011 Boudewijn Rempt (boud@valdyas.org) Copyright (C) 2007, 2009, 2010 Thomas Zander Copyright (c) 2008 Carlos Licea This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KO_RESOURCEMANAGER_P_H #define KO_RESOURCEMANAGER_P_H #include #include #include #include "kritaflake_export.h" #include #include #include "KoDerivedResourceConverter.h" #include "KoResourceUpdateMediator.h" class KoShape; class QVariant; class KRITAFLAKE_EXPORT KoResourceManager : public QObject { Q_OBJECT public: KoResourceManager() {} /** * Set a resource of any type. * @param key the integer key * @param value the new value for the key. * @see KoCanvasResourceProvider::CanvasResource KoDocumentResourceManager::DocumentResource */ void setResource(int key, const QVariant &value); /** * Set a resource of type KoColor. * @param key the integer key * @param color the new value for the key. * @see KoCanvasResourceProvider::CanvasResource KoDocumentResourceManager::DocumentResource */ void setResource(int key, const KoColor &color); /** * Set a resource of type KoShape*. * @param key the integer key - * @param id the new value for the key. + * @param shape the new shape for the key. * @see KoCanvasResourceProvider::CanvasResource KoDocumentResourceManager::DocumentResource */ void setResource(int key, KoShape *shape); /** * Set a resource of type KoUnit * @param key the integer key - * @param id the new value for the key. + * @param unit the unit for the key. * @see KoCanvasResourceProvider::CanvasResource KoDocumentResourceManager::DocumentResource */ void setResource(int key, const KoUnit &unit); /** * Returns a qvariant containing the specified resource or a standard one if the * specified resource does not exist. * @param key the key * @see KoCanvasResourceProvider::CanvasResource KoDocumentResourceManager::DocumentResource */ QVariant resource(int key) const; /** * Return the resource determined by param key as a boolean. * @param key the identifying key for the resource * @see KoCanvasResourceProvider::CanvasResource KoDocumentResourceManager::DocumentResource */ bool boolResource(int key) const; /** * Return the resource determined by param key as an integer. * @param key the identifying key for the resource * @see KoCanvasResourceProvider::CanvasResource KoDocumentResourceManager::DocumentResource */ int intResource(int key) const; /** * Return the resource determined by param key as a KoColor. * @param key the identifying key for the resource * @see KoCanvasResourceProvider::CanvasResource KoDocumentResourceManager::DocumentResource */ KoColor koColorResource(int key) const; /** * Return the resource determined by param key as a pointer to a KoShape. * @param key the identifying key for the resource * @see KoCanvasResourceProvider::CanvasResource KoDocumentResourceManager::DocumentResource */ KoShape *koShapeResource(int key) const; /** * Return the resource determined by param key as a QString . * @param key the identifying key for the resource * @see KoCanvasResourceProvider::CanvasResource KoDocumentResourceManager::DocumentResource */ QString stringResource(int key) const; /** * Return the resource determined by param key as a QSizeF. * @param key the identifying key for the resource * @see KoCanvasResourceProvider::CanvasResource KoDocumentResourceManager::DocumentResource */ QSizeF sizeResource(int key) const; /** * Return the resource determined by param key as a KoUnit. * @param key the identifying key for the resource * @see KoCanvasResourceProvider::CanvasResource KoDocumentResourceManager::DocumentResource */ KoUnit unitResource(int key) const; /** * Returns true if there is a resource set with the requested key. * @param key the identifying key for the resource * @see KoCanvasResourceProvider::CanvasResource KoDocumentResourceManager::DocumentResource */ bool hasResource(int key) const; /** * Remove the resource with @p key from the provider. * @param key the key that will be used to remove the resource * @see KoCanvasResourceProvider::CanvasResource KoDocumentResourceManager::DocumentResource */ void clearResource(int key); /** * Some of the resources may be "derived" from the others. For * example opacity, composite op and erase mode properties are * contained inside a paintop preset, so we need not create a * separate resource for them. Instead we created a derived resource, * that loads/saves values from/to another resource, but has its own * "resource changed" signal (via a different key). * * When a parent resource changes, the resource manager emits * update signals for all its derived resources. */ void addDerivedResourceConverter(KoDerivedResourceConverterSP converter); /** * @return true if the resource with \p key is a derived resource * (has a converter installed) * * @see addDerivedResourceConverter() */ bool hasDerivedResourceConverter(int key); /** * Removes a derived resource converter. If you rty to add a * resource with \p key it will be treated as a usual resource. * * @see addDerivedResourceConverter() */ void removeDerivedResourceConverter(int key); /** * Some resources can "mutate", that is their value doesn't change * (a pointer), whereas the contents changes. But we should still * notify all the derived resources subscribers that the resource * has changed. For that purpose we use a special mediator class * that connects the resource (which is not a QObject at all) and * the resource manager controls that connection. */ void addResourceUpdateMediator(KoResourceUpdateMediatorSP mediator); /** * \see addResourceUpdateMediator() */ bool hasResourceUpdateMediator(int key); /** * \see addResourceUpdateMediator() */ void removeResourceUpdateMediator(int key); Q_SIGNALS: void resourceChanged(int key, const QVariant &value); private: void notifyResourceChanged(int key, const QVariant &value); void notifyDerivedResourcesChanged(int key, const QVariant &value); private Q_SLOTS: void slotResourceInternalsChanged(int key); private: KoResourceManager(const KoResourceManager&); KoResourceManager& operator=(const KoResourceManager&); QHash m_resources; QHash m_derivedResources; QMultiHash m_derivedFromSource; QHash m_updateMediators; }; #endif diff --git a/libs/flake/KoSelection.h b/libs/flake/KoSelection.h index 0444813f75..b3e86b1729 100644 --- a/libs/flake/KoSelection.h +++ b/libs/flake/KoSelection.h @@ -1,169 +1,165 @@ /* This file is part of the KDE project Copyright (C) 2006 Boudewijn Rempt Copyright (C) 2006 Thorsten Zachmann Copyright (C) 2007,2009 Thomas Zander Copyright (C) 2006,2007 Jan Hambrecht This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOSELECTION_H #define KOSELECTION_H #include #include "KoShape.h" #include "KoFlake.h" #include "kritaflake_export.h" class KoViewConverter; class KoShapeLayer; class KoSelectionPrivate; /** * A selection is a shape that contains a number of references * to shapes. That means that a selection can be manipulated in * the same way as a single shape. * * Note that a single shape can be selected in one view, and not in * another, and that in a single view, more than one selection can be * present. So selections should not be seen as singletons, or as * something completely transient. * * A selection, however, should not be selectable. We need to think * a little about the interaction here. */ class KRITAFLAKE_EXPORT KoSelection : public QObject, public KoShape, public KoShape::ShapeChangeListener { Q_OBJECT public: KoSelection(); ~KoSelection() override; void paint(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintcontext) override; void setSize(const QSizeF &size) override; QSizeF size() const override; QRectF outlineRect() const override; QRectF boundingRect() const override; /** * Adds a shape to the selection. * * If the shape is a KoShapeGroup all of its child shapes are automatically added * to the selection. * If the shape has no parent or is not a KoShapeGroup, only the given shape is * added to the selection. * If the given shape is a child of a KoShapeGroup and recursive selection is enabled * the all parents and their child shapes up to the toplevel KoShapeGroup are added to * the selection. * * @param shape the shape to add to the selection - * @param recursive enables recursively selecting shapes of parent groups */ void select(KoShape *shape); /** * Removes a selected shape. * * If the shape is a KoShapeGroup all of its child shapes are automatically removed * from the selection. * If the shape has no parent or is not a KoShapeGroup, only the given shape is * removed from the selection. * If the given shape is a child of a KoShapeGroup and recursive selection is enabled * the all parents and their child shape up to the toplevel KoShapeGroup are removed * from the selection. * * @param shape the shape to remove from the selection - * @param recursive enables recursively deselecting shapes of parent groups */ void deselect(KoShape *shape); /// clear the selections list void deselectAll(); /** * Return the list of selected shapes * @return the list of selected shapes */ const QList selectedShapes() const; /** * Same as selectedShapes() but only for shapes in visible state. Used by * the algorithms that draw shapes on the image */ const QList selectedVisibleShapes() const; /** * Same as selectedShapes() but only for editable shapes. Used by * the algorithms that modify the image */ const QList selectedEditableShapes() const; /** * Same as selectedEditableShapes() but also includes shapes delegates. * Used for */ const QList selectedEditableShapesAndDelegates() const; /** * Return the first selected shape, or 0 if there is nothing selected. - * @param strip if StrippedSelection, the returned list will not include any children - * of a grouped shape if the group-parent is itself also in the set. */ KoShape *firstSelectedShape() const; /// return true if the shape is selected bool isSelected(const KoShape *shape) const; /// return the selection count, i.e. the number of all selected shapes int count() const; bool hitTest(const QPointF &position) const override; /** * Sets the currently active layer. * @param layer the new active layer */ void setActiveLayer(KoShapeLayer *layer); /** * Returns a currently active layer. * * @return the currently active layer, or zero if there is none */ KoShapeLayer *activeLayer() const; void notifyShapeChanged(ChangeType type, KoShape *shape) override; Q_SIGNALS: /// emitted when the selection is changed void selectionChanged(); /// emitted when the current layer is changed void currentLayerChanged(const KoShapeLayer *layer); private: void saveOdf(KoShapeSavingContext &) const override; bool loadOdf(const KoXmlElement &, KoShapeLoadingContext &) override; Q_DECLARE_PRIVATE_D(KoShape::d_ptr, KoSelection) }; #endif diff --git a/libs/flake/KoShape.h b/libs/flake/KoShape.h index 8786cd679f..50fb9ee339 100644 --- a/libs/flake/KoShape.h +++ b/libs/flake/KoShape.h @@ -1,1303 +1,1305 @@ /* This file is part of the KDE project Copyright (C) 2006-2008 Thorsten Zachmann Copyright (C) 2006, 2008 C. Boemann Copyright (C) 2006-2010 Thomas Zander Copyright (C) 2007-2009,2011 Jan Hambrecht This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOSHAPE_H #define KOSHAPE_H #include "KoFlake.h" #include "KoFlakeTypes.h" #include "KoConnectionPoint.h" #include #include #include #include #include "kritaflake_export.h" class QPainter; class QRectF; class QPainterPath; class QTransform; class KoShapeContainer; class KoShapeStrokeModel; class KoShapeUserData; class KoViewConverter; class KoShapeApplicationData; class KoShapeSavingContext; class KoShapeLoadingContext; class KoGenStyle; class KoShapeShadow; class KoShapePrivate; class KoFilterEffectStack; class KoSnapData; class KoClipPath; class KoClipMask; class KoShapePaintingContext; class KoShapeAnchor; class KoBorder; struct KoInsets; class KoShapeBackground; class KisHandlePainterHelper; /** * Base class for all flake shapes. Shapes extend this class * to allow themselves to be manipulated. This class just represents * a graphical shape in the document and can be manipulated by some default * tools in this library. * * Due to the limited responsibility of this class, the extending object * can have any data backend and is responsible for painting itself. * * We strongly suggest that any extending class will use a Model View * Controller (MVC) design where the View part is all in this class, as well * as the one that inherits from this one. This allows the data that rests * in the model to be reused in different parts of the document. For example * by having two flake objects that show that same data. Or each showing a section of it. * * The KoShape data is completely in postscript-points (pt) (see KoUnit * for conversion methods to and from points). * This image will explain the real-world use of the shape and its options. *
* The Rotation center can be returned with absolutePosition() * *

Flake objects can be created in three ways: *

    *
  • a simple new KoDerivedFlake(), *
  • through an associated tool, *
  • through a factory *
* *

Shape interaction notifications

* We had several notification methods that allow your shape to be notified of changes in other * shapes positions or rotation etc. *
  1. The most general is KoShape::shapeChanged().
    * a virtual method that you can use to check various changed to your shape made by tools or otherwise.
  2. *
  3. for shape hierarchies the parent may receive a notification when a child was modified. * This is done though KoShapeContainerModel::childChanged()
  4. *
  5. any shape that is at a similar position as another shape there is collision detection. * You can register your shape to be sensitive to any changes like moving or whatever to * other shapes that intersect yours. * Such changes will then be notified to your shape using the method from (1) You should call * KoShape::setCollisionDetection(bool) to enable this. *
*/ class KRITAFLAKE_EXPORT KoShape { public: /// Used by shapeChanged() to select which change was made enum ChangeType { PositionChanged, ///< used after a setPosition() RotationChanged, ///< used after a setRotation() ScaleChanged, ///< used after a scale() ShearChanged, ///< used after a shear() SizeChanged, ///< used after a setSize() GenericMatrixChange, ///< used after the matrix was changed without knowing which property explicitly changed KeepAspectRatioChange, ///< used after setKeepAspectRatio() ParentChanged, ///< used after a setParent() CollisionDetected, ///< used when another shape moved in our boundingrect Deleted, ///< the shape was deleted StrokeChanged, ///< the shapes stroke has changed BackgroundChanged, ///< the shapes background has changed ShadowChanged, ///< the shapes shadow has changed BorderChanged, ///< the shapes border has changed ParameterChanged, ///< the shapes parameter has changed (KoParameterShape only) ContentChanged, ///< the content of the shape changed e.g. a new image inside a pixmap/text change inside a textshape TextRunAroundChanged, ///< used after a setTextRunAroundSide() ChildChanged, ///< a child of a container was changed/removed. This is propagated to all parents ConnectionPointChanged, ///< a connection point has changed ClipPathChanged, ///< the shapes clip path has changed TransparencyChanged ///< the shapetransparency value has changed }; /// The behavior text should do when intersecting this shape. enum TextRunAroundSide { BiggestRunAroundSide, ///< Run other text around the side that has the most space LeftRunAroundSide, ///< Run other text around the left side of the frame RightRunAroundSide, ///< Run other text around the right side of the frame EnoughRunAroundSide, ///< Run other text dynamically around both sides of the shape, provided there is sufficient space left BothRunAroundSide, ///< Run other text around both sides of the shape NoRunAround, ///< The text will be completely avoiding the frame by keeping the horizontal space that this frame occupies blank. RunThrough ///< The text will completely ignore the frame and layout as if it was not there }; /// The behavior text should do when intersecting this shape. enum TextRunAroundContour { ContourBox, /// Run other text around a bounding rect of the outline ContourFull, ///< Run other text around also on the inside ContourOutside ///< Run other text around only on the outside }; /** * TODO */ enum RunThroughLevel { Background, Foreground }; /** * @brief Constructor */ KoShape(); /** * @brief Destructor */ virtual ~KoShape(); /** * @brief creates a deep copy of the shape or shape's subtree * @return a cloned shape */ virtual KoShape* cloneShape() const; /** * @brief Paint the shape fill * The class extending this one is responsible for painting itself. Since we do not * assume the shape is square the paint must also clear its background if it will draw * something transparent on top. * This can be done with a method like: * painter.fillRect(converter.normalToView(QRectF(QPointF(0.0,0.0), size())), background()); * Or equivalent for non-square objects. * Do note that a shape's top-left is always at coordinate 0,0. Even if the shape itself is rotated * or translated. * @param painter used for painting the shape * @param converter to convert between internal and view coordinates. * @see applyConversion() * @param paintcontext the painting context. */ virtual void paint(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintcontext) = 0; /** * @brief paintStroke paints the shape's stroked outline * @param painter used for painting the shape * @param converter to convert between internal and view coordinates. * @see applyConversion() * @param paintcontext the painting context. */ virtual void paintStroke(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintcontext); /** * @brief Paint the shape's border * This is a helper function that could be called from the paint() method of all shapes. * @param painter used for painting the shape * @param converter to convert between internal and view coordinates. * @see applyConversion() */ virtual void paintBorder(QPainter &painter, const KoViewConverter &converter); /** * Load a shape from odf * * @param context the KoShapeLoadingContext used for loading * @param element element which represents the shape in odf * * @return false if loading failed */ virtual bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) = 0; /** * @brief store the shape data as ODF XML. * This is the method that will be called when saving a shape as a described in * OpenDocument 9.2 Drawing Shapes. * @see saveOdfAttributes */ virtual void saveOdf(KoShapeSavingContext &context) const = 0; /** * This method can be used while saving the shape as ODF to add the data * stored on this shape to the current element. * * @param context the context for the current save. * @param attributes a number of OdfAttribute items to state which attributes to save. * @see saveOdf */ void saveOdfAttributes(KoShapeSavingContext &context, int attributes) const; /** * This method can be used while saving the shape as Odf to add common child elements * * The office:event-listeners and draw:glue-point are saved. * @param context the context for the current save. */ void saveOdfCommonChildElements(KoShapeSavingContext &context) const; /** * This method can be used to save contour data from the clipPath() * * The draw:contour-polygon or draw:contour-path elements are saved. * @param context the context for the current save. * @param originalSize the original size of the unscaled image. */ void saveOdfClipContour(KoShapeSavingContext &context, const QSizeF &originalSize) const; /** * @brief Scale the shape using the zero-point which is the top-left corner. * @see position() * * @param sx scale in x direction * @param sy scale in y direction */ void scale(qreal sx, qreal sy); /** * @brief Rotate the shape (relative) * * The shape will be rotated from the current rotation using the center of the shape using the size() * * @param angle change the angle of rotation increasing it with 'angle' degrees */ void rotate(qreal angle); /** * Return the current rotation in degrees. * It returns NaN if the shape has a shearing or scaling transformation applied. */ qreal rotation() const; /** * @brief Shear the shape * The shape will be sheared using the zero-point which is the top-left corner. * @see position() * * @param sx shear in x direction * @param sy shear in y direction */ void shear(qreal sx, qreal sy); /** * @brief Resize the shape * * @param size the new size of the shape. This is different from scaling as * scaling is a so called secondary operation which is comparable to zooming in * instead of changing the size of the basic shape. * Easiest example of this difference is that using this method will not distort the * size of pattern-fills and strokes. */ virtual void setSize(const QSizeF &size); /** * @brief Get the size of the shape in pt. * * The size is in shape coordinates. * * @return the size of the shape as set by setSize() */ virtual QSizeF size() const; /** * @brief Set the position of the shape in pt * * @param position the new position of the shape */ virtual void setPosition(const QPointF &position); /** * @brief Get the position of the shape in pt * * @return the position of the shape */ QPointF position() const; /** * @brief Check if the shape is hit on position * @param position the position where the user clicked. * @return true when it hits. */ virtual bool hitTest(const QPointF &position) const; /** * @brief Get the bounding box of the shape * * This includes the line width and the shadow of the shape * * @return the bounding box of the shape */ virtual QRectF boundingRect() const; /** * Get the united bounding box of a group of shapes. This is a utility * function used in many places in Krita. */ static QRectF boundingRect(const QList &shapes); /** * @return the bounding rect of the outline of the shape measured * in absolute coordinate system. Please note that in contrast to * boundingRect() this rect doesn't include the stroke and other * insets. */ QRectF absoluteOutlineRect(KoViewConverter *converter = 0) const; /** * Same as a member function, but applies to a list of shapes and returns a * united rect. */ static QRectF absoluteOutlineRect(const QList &shapes, KoViewConverter *converter = 0); /** * @brief Add a connector point to the shape * * A connector is a place on the shape that allows a graphical connection to be made * using a line, for example. * * @param point the connection point to add * @return the id of the new connection point */ int addConnectionPoint(const KoConnectionPoint &point); /** * Sets data of connection point with specified id. * * The position of the connector is restricted to the bounding rectangle of the shape. * When setting a default connection point, the new position is ignored, as these * are fixed at their default position. * The function will insert a new connection point if the specified id was not used * before. * * @param connectionPointId the id of the connection point to set * @param point the connection point data * @return false if specified connection point id is invalid, else true */ bool setConnectionPoint(int connectionPointId, const KoConnectionPoint &point); /// Checks if a connection point with the specified id exists bool hasConnectionPoint(int connectionPointId) const; /// Returns connection point with specified connection point id KoConnectionPoint connectionPoint(int connectionPointId) const; /** * Return a list of the connection points that have been added to this shape. * All the points are relative to the shape position, see absolutePosition(). * @return a list of the connectors that have been added to this shape. */ KoConnectionPoints connectionPoints() const; /// Removes connection point with specified id void removeConnectionPoint(int connectionPointId); /// Removes all connection points void clearConnectionPoints(); /** * Return the side text should flow around this shape. This implements the ODF style:wrap * attribute that specifies how text is displayed around a frame or graphic object. */ TextRunAroundSide textRunAroundSide() const; /** * Set the side text should flow around this shape. * @param side the requested side - * @param runThrought run through the foreground or background or... + * @param runThrough run through the foreground or background or... */ void setTextRunAroundSide(TextRunAroundSide side, RunThroughLevel runThrough = Background); /** * The space between this shape's left edge and text that runs around this shape. * @return the space around this shape to keep free from text */ qreal textRunAroundDistanceLeft() const; /** * Set the space between this shape's left edge and the text that run around this shape. * @param distance the space around this shape to keep free from text */ void setTextRunAroundDistanceLeft(qreal distance); /** * The space between this shape's top edge and text that runs around this shape. * @return the space around this shape to keep free from text */ qreal textRunAroundDistanceTop() const; /** * Set the space between this shape's top edge and the text that run around this shape. * @param distance the space around this shape to keep free from text */ void setTextRunAroundDistanceTop(qreal distance); /** * The space between this shape's right edge and text that runs around this shape. * @return the space around this shape to keep free from text */ qreal textRunAroundDistanceRight() const; /** * Set the space between this shape's right edge and the text that run around this shape. * @param distance the space around this shape to keep free from text */ void setTextRunAroundDistanceRight(qreal distance); /** * The space between this shape's bottom edge and text that runs around this shape. * @return the space around this shape to keep free from text */ qreal textRunAroundDistanceBottom() const; /** * Set the space between this shape's bottom edge and the text that run around this shape. * @param distance the space around this shape to keep free from text */ void setTextRunAroundDistanceBottom(qreal distance); /** * Return the threshold above which text should flow around this shape. * The text will not flow around the shape on a side unless the space available on that side * is above this threshold. Only used when the text run around side is EnoughRunAroundSide. * @return threshold the threshold */ qreal textRunAroundThreshold() const; /** * Set the threshold above which text should flow around this shape. * The text will not flow around the shape on a side unless the space available on that side * is above this threshold. Only used when the text run around side is EnoughRunAroundSide. * @param threshold the new threshold */ void setTextRunAroundThreshold(qreal threshold); /** * Return the how tight text run around is done around this shape. * @return the contour */ TextRunAroundContour textRunAroundContour() const; /** * Set how tight text run around is done around this shape. * @param contour the new contour */ void setTextRunAroundContour(TextRunAroundContour contour); /** * Set the KoShapeAnchor */ void setAnchor(KoShapeAnchor *anchor); /** * Return the KoShapeAnchor, or 0 */ KoShapeAnchor *anchor() const; /** * Set the minimum height of the shape. * Currently it's not respected but only for informational purpose - * @param minimumShapeHeight the minimum height of the frame. + * @param height the minimum height of the frame. */ void setMinimumHeight(qreal height); /** * Return the minimum height of the shape. * @return the minimum height of the shape. Default is 0.0. */ qreal minimumHeight() const; /** * Set the background of the shape. * A shape background can be a plain color, a gradient, a pattern, be fully transparent * or have a complex fill. * Setting such a background will allow the shape to be filled and will be able to tell * if it is transparent or not. * * If the shape inherited the background from its parent, its stops inheriting it, that * is inheritBackground property resets to false. * * @param background the new shape background. */ void setBackground(QSharedPointer background); /** * return the brush used to paint te background of this shape with. * A QBrush can have a plain color, be fully transparent or have a complex fill. * setting such a brush will allow the shape to fill itself using that brush and * will be able to tell if its transparent or not. * @return the background-brush */ QSharedPointer background() const; /** * @brief setInheritBackground marks a shape as inhiriting the background * from the parent shape. NOTE: The currently selected background is destroyed. * @param value true if the shape should inherit the filling background */ void setInheritBackground(bool value); /** * @brief inheritBackground shows if the shape inherits background from its parent * @return true if the shape inherits the fill */ bool inheritBackground() const; /** * Returns true if there is some transparency, false if the shape is fully opaque. * The default implementation will just return if the background has some transparency, * you should override it and always return true if your shape is not square. * @return if the shape is (partly) transparent. */ virtual bool hasTransparency() const; /** * Sets shape level transparency. * @param transparency the new shape level transparency */ void setTransparency(qreal transparency); /** * Returns the shape level transparency. * @param recursive when true takes the parents transparency into account */ qreal transparency(bool recursive=false) const; /** * Retrieve the z-coordinate of this shape. * The zIndex property is used to determine which shape lies on top of other objects. * An shape with a higher z-order is on top, and can obscure another shape. * @return the z-index of this shape. * @see setZIndex() */ qint16 zIndex() const; /** * Set the z-coordinate of this shape. * The zIndex property is used to determine which shape lies on top of other objects. * An shape with a higher z-order is on top, and can obscure, another shape. *

Just like two objects having the same x or y coordinate will make them 'touch', * so will two objects with the same z-index touch on the z plane. In layering the * shape this, however, can cause a little confusion as one always has to be on top. * The layering if two overlapping objects have the same index is implementation dependent * and probably depends on the order in which they are added to the shape manager. * @param zIndex the new z-index; */ void setZIndex(qint16 zIndex); /** * Maximum value of z-index */ static const qint16 maxZIndex; /** * Minimum value of z-index */ static const qint16 minZIndex; /** * Retrieve the run through property of this shape. * The run through property is used to determine if the shape is behind, inside or before text. * @return the run through of this shape. */ int runThrough(); /** * Set the run through property of this shape. * The run through property is used to determine if the shape is behind, inside or before text. * @param runThrough the new run through; */ virtual void setRunThrough(short int runThrough); /** * Changes the Shape to be visible or invisible. * Being visible means being painted, as well as being used for * things like guidelines or searches. * @param on when true; set the shape to be visible. * @see setGeometryProtected(), setContentProtected(), setSelectable() */ void setVisible(bool on); /** * Returns current visibility state of this shape. * Being visible means being painted, as well as being used for * things like guidelines or searches. * @param recursive when true, checks visibility recursively * @return current visibility state of this shape. * @see isGeometryProtected(), isContentProtected(), isSelectable() */ bool isVisible(bool recursive = true) const; /** * Changes the shape to be printable or not. The default is true. * * If a Shape's print flag is true, the shape will be printed. If * false, the shape will not be printed. If a shape is not visible (@see isVisible), * it isPrinted will return false, too. */ void setPrintable(bool on); /** * Returns the current printable state of this shape. * * A shape can be visible but not printable, not printable and not visible * or visible and printable, but not invisible and still printable. * * @return current printable state of this shape. */ bool isPrintable() const; /** * Makes it possible for the user to select this shape. * This parameter defaults to true. * @param selectable when true; set the shape to be selectable by the user. * @see setGeometryProtected(), setContentProtected(), setVisible() */ void setSelectable(bool selectable); /** * Returns if this shape can be selected by the user. * @return true only when the object is selectable. * @see isGeometryProtected(), isContentProtected(), isVisible() */ bool isSelectable() const; /** * Tells the shape to have its position/rotation and size protected from user-changes. * The geometry being protected means the user can not change shape or position of the * shape. This includes any matrix operation such as rotation. * @param on when true; set the shape to have its geometry protected. * @see setContentProtected(), setSelectable(), setVisible() */ void setGeometryProtected(bool on); /** * Returns current geometry protection state of this shape. * The geometry being protected means the user can not change shape or position of the * shape. This includes any matrix operation such as rotation. * @return current geometry protection state of this shape. * @see isContentProtected(), isSelectable(), isVisible() */ bool isGeometryProtected() const; /** * Marks the shape to have its content protected against editing. * Content protection is a hint for tools to disallow the user editing the content. * @param protect when true set the shapes content to be protected from user modification. * @see setGeometryProtected(), setSelectable(), setVisible() */ void setContentProtected(bool protect); /** * Returns current content protection state of this shape. * Content protection is a hint for tools to disallow the user editing the content. * @return current content protection state of this shape. * @see isGeometryProtected(), isSelectable(), isVisible() */ bool isContentProtected() const; /** * Returns the parent, or 0 if there is no parent. * @return the parent, or 0 if there is no parent. */ KoShapeContainer *parent() const; /** * Set the parent of this shape. * @param parent the new parent of this shape. Can be 0 if the shape has no parent anymore. */ void setParent(KoShapeContainer *parent); /** * @brief inheritsTransformFromAny checks if the shape inherits transformation from * any of the shapes listed in \p ancestorsInQuestion. The inheritance is checked * in recursive way. * @return true if there is a (transitive) transformation-wise parent found in \p ancestorsInQuestion */ bool inheritsTransformFromAny(const QList ancestorsInQuestion) const; /** * @return true if this shape has a common parent with \p shape */ bool hasCommonParent(const KoShape *shape) const; /** * Request a repaint to be queued. * The repaint will be of the entire Shape, including its selection handles should this * shape be selected. *

This method will return immediately and only request a repaint. Successive calls * will be merged into an appropriate repaint action. */ virtual void update() const; /** * Request a repaint to be queued. * The repaint will be restricted to the parameters rectangle, which is expected to be * in absolute coordinates of the canvas and it is expected to be * normalized. *

This method will return immediately and only request a repaint. Successive calls * will be merged into an appropriate repaint action. * @param rect the rectangle (in pt) to queue for repaint. */ virtual void updateAbsolute(const QRectF &rect) const; /// Used by compareShapeZIndex() to order shapes enum ChildZOrderPolicy { ChildZDefault, ChildZParentChild = ChildZDefault, ///< normal parent/child ordering ChildZPassThrough ///< children are considered equal to this shape }; /** * Returns if during compareShapeZIndex() how this shape portrays the values * of its children. The default behaviour is to let this shape's z values take * the place of its childrens values, so you get a parent/child relationship. * The children are naturally still ordered relatively to their z values * * But for special cases (like Calligra's TextShape) it can be overloaded to return * ChildZPassThrough which means the children keep their own z values * @returns the z order policy of this shape */ virtual ChildZOrderPolicy childZOrderPolicy(); /** * This is a method used to sort a list using the STL sorting methods. * @param s1 the first shape * @param s2 the second shape */ static bool compareShapeZIndex(KoShape *s1, KoShape *s2); /** * returns the outline of the shape in the form of a path. * The outline returned will always be relative to the position() of the shape, so * moving the shape will not alter the result. The outline is used to draw the stroke * on, for example. * @returns the outline of the shape in the form of a path. */ virtual QPainterPath outline() const; /** * returns the outline of the shape in the form of a rect. * The outlineRect returned will always be relative to the position() of the shape, so * moving the shape will not alter the result. The outline is used to calculate * the boundingRect. * @returns the outline of the shape in the form of a rect. */ virtual QRectF outlineRect() const; /** * returns the outline of the shape in the form of a path for the use of painting a shadow. * * Normally this would be the same as outline() if there is a fill (background) set on the * shape and empty if not. However, a shape could reimplement this to return an outline * even if no fill is defined. A typical example of this would be the picture shape * which has a picture but almost never a background. * * @returns the outline of the shape in the form of a path. */ virtual QPainterPath shadowOutline() const; /** * Returns the currently set stroke, or 0 if there is no stroke. * @return the currently set stroke, or 0 if there is no stroke. */ KoShapeStrokeModelSP stroke() const; /** * Set a new stroke, removing the old one. The stroke inheritance becomes disabled. * @param stroke the new stroke, or 0 if there should be no stroke. */ void setStroke(KoShapeStrokeModelSP stroke); /** * @brief setInheritStroke marks a shape as inhiriting the stroke * from the parent shape. NOTE: The currently selected stroke is destroyed. * @param value true if the shape should inherit the stroke style */ void setInheritStroke(bool value); /** * @brief inheritStroke shows if the shape inherits the stroke from its parent * @return true if the shape inherits the stroke style */ bool inheritStroke() const; /** * Return the insets of the stroke. * Convenience method for KoShapeStrokeModel::strokeInsets() */ KoInsets strokeInsets() const; /// Sets the new shadow, removing the old one void setShadow(KoShapeShadow *shadow); /// Returns the currently set shadow or 0 if there is no shadow set KoShapeShadow *shadow() const; /// Sets the new border, removing the old one. void setBorder(KoBorder *border); /// Returns the currently set border or 0 if there is no border set KoBorder *border() const; /// Sets a new clip path, removing the old one void setClipPath(KoClipPath *clipPath); /// Returns the currently set clip path or 0 if there is no clip path set KoClipPath * clipPath() const; /// Sets a new clip mask, removing the old one. The mask is owned by the shape. void setClipMask(KoClipMask *clipMask); /// Returns the currently set clip mask or 0 if there is no clip mask set KoClipMask* clipMask() const; /** * Setting the shape to keep its aspect-ratio has the effect that user-scaling will * keep the width/height ratio intact so as not to distort shapes that rely on that * ratio. * @param keepAspect the new value */ void setKeepAspectRatio(bool keepAspect); /** * Setting the shape to keep its aspect-ratio has the effect that user-scaling will * keep the width/height ratio intact so as not to distort shapes that rely on that * ratio. * @return whether to keep aspect ratio of this shape */ bool keepAspectRatio() const; /** * Return the position of this shape regardless of rotation/skew/scaling and regardless of * this shape having a parent (being in a group) or not.
* @param anchor The place on the (unaltered) shape that you want the position of. * @return the point that is the absolute, centered position of this shape. */ QPointF absolutePosition(KoFlake::AnchorPosition anchor = KoFlake::Center) const; /** * Move this shape to an absolute position where the end location will be the same * regardless of the shape's rotation/skew/scaling and regardless of this shape having * a parent (being in a group) or not.
* The newPosition is going to be the center of the shape. * This has the convenient effect that:

     shape->setAbsolutePosition(QPointF(0,0));
     shape->rotate(45);
Will result in the same visual position of the shape as the opposite:
     shape->rotate(45);
     shape->setAbsolutePosition(QPointF(0,0));
* @param newPosition the new absolute center of the shape. * @param anchor The place on the (unaltered) shape that you set the position of. */ void setAbsolutePosition(const QPointF &newPosition, KoFlake::AnchorPosition anchor = KoFlake::Center); /** * Set a data object on the shape to be used by an application. * This is specifically useful when a shape is created in a plugin and that data from that * shape should be accessible outside the plugin. * @param userData the new user data, or 0 to delete the current one. */ void setUserData(KoShapeUserData *userData); /** * Return the current userData. */ KoShapeUserData *userData() const; /** * Return the Id of this shape, identifying the type of shape by the id of the factory. * @see KoShapeFactoryBase::shapeId() * @return the id of the shape-type */ QString shapeId() const; /** * Set the Id of this shape. A shapeFactory is expected to set the Id at creation * so applications can find out what kind of shape this is. * @see KoShapeFactoryBase::shapeId() * @param id the ID from the factory that created this shape */ void setShapeId(const QString &id); /** * Create a matrix that describes all the transformations done on this shape. * * The absolute transformation is the combined transformation of this shape * and all its parents and grandparents. * * @param converter if not null, this method uses the converter to mark the right * offsets in the current view. */ QTransform absoluteTransformation(const KoViewConverter *converter) const; /** * Applies a transformation to this shape. * * The transformation given is relative to the global coordinate system, i.e. the document. * This is a convenience function to apply a global transformation to this shape. * @see applyTransformation * * @param matrix the transformation matrix to apply */ void applyAbsoluteTransformation(const QTransform &matrix); /** * Sets a new transformation matrix describing the local transformations on this shape. * @param matrix the new transformation matrix */ void setTransformation(const QTransform &matrix); /// Returns the shapes local transformation matrix QTransform transformation() const; /** * Applies a transformation to this shape. * * The transformation given is relative to the shape coordinate system. * * @param matrix the transformation matrix to apply */ void applyTransformation(const QTransform &matrix); /** * Copy all the settings from the parameter shape and apply them to this shape. * Settings like the position and rotation to visible and locked. The parent * is a notable exclusion. * @param shape the shape to use as original */ void copySettings(const KoShape *shape); /** * Convenience method that allows people implementing paint() to use the shape * internal coordinate system directly to paint itself instead of considering the * views zoom. * @param painter the painter to alter the zoom level of. * @param converter the converter for the current views zoom. */ static void applyConversion(QPainter &painter, const KoViewConverter &converter); /** * A convenience method that creates a handles helper with applying transformations at * the same time. Please note that you shouldn't save/restore additionally. All the work * on restoring original painter's transformations is done by the helper. */ static KisHandlePainterHelper createHandlePainterHelper(QPainter *painter, KoShape *shape, const KoViewConverter &converter, qreal handleRadius = 0.0); /** * @brief Transforms point from shape coordinates to document coordinates * @param point in shape coordinates * @return point in document coordinates */ QPointF shapeToDocument(const QPointF &point) const; /** * @brief Transforms rect from shape coordinates to document coordinates * @param rect in shape coordinates * @return rect in document coordinates */ QRectF shapeToDocument(const QRectF &rect) const; /** * @brief Transforms point from document coordinates to shape coordinates * @param point in document coordinates * @return point in shape coordinates */ QPointF documentToShape(const QPointF &point) const; /** * @brief Transform rect from document coordinates to shape coordinates * @param rect in document coordinates * @return rect in shape coordinates */ QRectF documentToShape(const QRectF &rect) const; /** * Returns the name of the shape. * @return the shapes name */ QString name() const; /** * Sets the name of the shape. * @param name the new shape name */ void setName(const QString &name); /** * Update the position of the shape in the tree of the KoShapeManager. */ void notifyChanged(); /** * A shape can be in a state that it is doing processing data like loading or text layout. * In this case it can be shown on screen probably partially but it should really not be printed * until it is fully done processing. * Warning! This method can be blocking for a long time + * @param converter The converter * @param asynchronous If set to true the processing will can take place in a different thread and the * function will not block until the shape is finished. * In case of printing Flake will call this method from a non-main thread and only * start printing it when the in case of printing method returned. * If set to false the processing needs to be done synchronously and will * block until the result is finished. */ virtual void waitUntilReady(const KoViewConverter &converter, bool asynchronous = true) const; /// checks recursively if the shape or one of its parents is not visible or locked virtual bool isShapeEditable(bool recursive = true) const; /** * Adds a shape which depends on this shape. * Making a shape dependent on this one means it will get shapeChanged() called * on each update of this shape. * * If this shape already depends on the given shape, establishing the * dependency is refused to prevent circular dependencies. * * @param shape the shape which depends on this shape * @return true if dependency could be established, otherwise false * @see removeDependee(), hasDependee() */ bool addDependee(KoShape *shape); /** * Removes as shape depending on this shape. * @see addDependee(), hasDependee() */ void removeDependee(KoShape *shape); /// Returns if the given shape is dependent on this shape bool hasDependee(KoShape *shape) const; /// Returns list of shapes depending on this shape QList dependees() const; /// Returns additional snap data the shape wants to have snapping to virtual KoSnapData snapData() const; /** * Set additional attribute * * This can be used to attach additional attributes to a shape for attributes * that are application specific like presentation:placeholder * * @param name The name of the attribute in the following form prefix:tag e.g. presentation:placeholder * @param value The value of the attribute */ void setAdditionalAttribute(const QString &name, const QString &value); /** * Remove additional attribute * * @param name The name of the attribute in the following form prefix:tag e.g. presentation:placeholder */ void removeAdditionalAttribute(const QString &name); /** * Check if additional attribute is set * * @param name The name of the attribute in the following form prefix:tag e.g. presentation:placeholder * * @return true if there is a attribute with prefix:tag set, false otherwise */ bool hasAdditionalAttribute(const QString &name) const; /** * Get additional attribute * * @param name The name of the attribute in the following form prefix:tag e.g. presentation:placeholder * * @return The value of the attribute if it exists or a null string if not found. */ QString additionalAttribute(const QString &name) const; void setAdditionalStyleAttribute(const char *name, const QString &value); void removeAdditionalStyleAttribute(const char *name); /** * Returns the filter effect stack of the shape * * @return the list of filter effects applied on the shape when rendering. */ KoFilterEffectStack *filterEffectStack() const; /// Sets the new filter effect stack, removing the old one void setFilterEffectStack(KoFilterEffectStack *filterEffectStack); /** * Set the property collision detection. * Setting this to true will result in calls to shapeChanged() with the CollisionDetected * parameter whenever either this or another shape is moved/rotated etc and intersects this shape. * @param detect if true detect collisions. */ void setCollisionDetection(bool detect); /** * get the property collision detection. * @returns true if collision detection is on. */ bool collisionDetection(); /** * Return the tool delegates for this shape. * In Flake a shape being selected will cause the tool manager to make available all tools that * can edit the selected shapes. In some cases selecting one shape should allow the tool to * edit a related shape be available too. The tool delegates allows this to happen by taking * all the shapes in the set into account on tool selection. * Notice that if the set is non-empty 'this' shape is no longer looked at. You can choose * to add itself to the set too. */ QSet toolDelegates() const; /** * Set the tool delegates. * @param delegates the new delegates. * @see toolDelegates() */ void setToolDelegates(const QSet &delegates); /** * Return the hyperlink for this shape. */ QString hyperLink () const; /** * Set hyperlink for this shape. * @param hyperLink name. */ void setHyperLink(const QString &hyperLink); /** * \internal * Returns the private object for use within the flake lib */ KoShapePrivate *priv(); public: struct KRITAFLAKE_EXPORT ShapeChangeListener { virtual ~ShapeChangeListener(); virtual void notifyShapeChanged(ChangeType type, KoShape *shape) = 0; private: friend class KoShape; friend class KoShapePrivate; void registerShape(KoShape *shape); void unregisterShape(KoShape *shape); void notifyShapeChangedImpl(ChangeType type, KoShape *shape); QList m_registeredShapes; }; void addShapeChangeListener(ShapeChangeListener *listener); void removeShapeChangeListener(ShapeChangeListener *listener); public: static QList linearizeSubtree(const QList &shapes); protected: /// constructor KoShape(KoShapePrivate *); /* ** loading saving helper methods */ /// attributes from ODF 1.1 chapter 9.2.15 Common Drawing Shape Attributes enum OdfAttribute { OdfTransformation = 1, ///< Store transformation information OdfSize = 2, ///< Store size information OdfPosition = 8, ///< Store position OdfAdditionalAttributes = 4, ///< Store additional attributes of the shape OdfCommonChildElements = 16, ///< Event actions and connection points OdfLayer = 64, ///< Store layer name OdfStyle = 128, ///< Store the style OdfId = 256, ///< Store the unique ID OdfName = 512, ///< Store the name of the shape OdfZIndex = 1024, ///< Store the z-index OdfViewbox = 2048, ///< Store the viewbox /// A mask for all mandatory attributes OdfMandatories = OdfLayer | OdfStyle | OdfId | OdfName | OdfZIndex, /// A mask for geometry attributes OdfGeometry = OdfPosition | OdfSize, /// A mask for all the attributes OdfAllAttributes = OdfTransformation | OdfGeometry | OdfAdditionalAttributes | OdfMandatories | OdfCommonChildElements }; /** * This method is used during loading of the shape to load common attributes * * @param context the KoShapeLoadingContext used for loading * @param element element which represents the shape in odf * @param attributes a number of OdfAttribute items to state which attributes to load. */ bool loadOdfAttributes(const KoXmlElement &element, KoShapeLoadingContext &context, int attributes); /** * Parses the transformation attribute from the given string * @param transform the transform attribute string * @return the resulting transformation matrix */ QTransform parseOdfTransform(const QString &transform); /** * @brief Saves the style used for the shape * * This method fills the given style object with the stroke and * background properties and then adds the style to the context. * * @param style the style object to fill * @param context used for saving * @return the name of the style * @see saveOdf */ virtual QString saveStyle(KoGenStyle &style, KoShapeSavingContext &context) const; /** * Loads the stroke and fill style from the given element. * * @param element the xml element to load the style from * @param context the loading context used for loading */ virtual void loadStyle(const KoXmlElement &element, KoShapeLoadingContext &context); /// Loads the stroke style KoShapeStrokeModelSP loadOdfStroke(const KoXmlElement &element, KoShapeLoadingContext &context) const; /// Loads the fill style QSharedPointer loadOdfFill(KoShapeLoadingContext &context) const; /// Loads the connection points void loadOdfGluePoints(const KoXmlElement &element, KoShapeLoadingContext &context); /// Loads the clip contour void loadOdfClipContour(const KoXmlElement &element, KoShapeLoadingContext &context, const QSizeF &scaleFactor); /* ** end loading saving */ /** * A hook that allows inheriting classes to do something after a KoShape property changed * This is called whenever the shape, position rotation or scale properties were altered. * @param type an indicator which type was changed. + * @param shape the shape. */ virtual void shapeChanged(ChangeType type, KoShape *shape = 0); /// return the current matrix that contains the rotation/scale/position of this shape QTransform transform() const; KoShapePrivate *d_ptr; private: Q_DECLARE_PRIVATE(KoShape) }; Q_DECLARE_METATYPE(KoShape*) #endif diff --git a/libs/flake/KoShapeContainer.h b/libs/flake/KoShapeContainer.h index c1b934dd07..3f31b9d8fc 100644 --- a/libs/flake/KoShapeContainer.h +++ b/libs/flake/KoShapeContainer.h @@ -1,251 +1,252 @@ /* This file is part of the KDE project * Copyright (C) 2006-2010 Thomas Zander * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOSHAPECONTAINER_H #define KOSHAPECONTAINER_H #include "KoShape.h" #include #include "kritaflake_export.h" class QPainter; class KoShapeContainerModel; class KoShapeContainerPrivate; class KoViewConverter; /** * This is the base class that all Flake group-shapes are based on. * Extending from this class allows you to have child-shapes. * Like the KoShape class, this shape is a visible class with * a position and a size. It can paint itself as well if you implement * the paintComponent() method. * *

The most important feature of this class is that you can make * other KoShape classes to be children of this container. * *

The effect of grouping those shapes is that their position * is relative to the position of the container. Move the container and * all children move with it. * *

Each child can optionally be said to be 'clipped' by the container. * This feature will give the effect that if the child has a size and * position outside the container, parts outside the container will not be shown. * This is especially useful * for showing cutouts of content, like images, without changing the actual content. * *

For so called clipped children any modification made to the container is * propagated to the child. This includes rotation as well as scaling * and shearing. * *

Maintaining the list of children can be done using the supplied methods * addChild() and removeChild(). However, they only forward their requests to the * data model KoShapeContainerModel and if you provide a custom implementation * of that model any means can be used to maintain a list of children, as long as * you will take care to register them with the appropriate shape manager. * *

An example usage where a custom model might be useful is when you have a * container for text areas which are split into columns. If you resize the container * and the width of the individual columns gets too small, the model can choose to * remove a child or add one when the width allows another column. */ class KRITAFLAKE_EXPORT KoShapeContainer : public KoShape { public: /** * Constructor with custom model to be used for maintaining the list of children. * For all the normal cases you don't need a custom model. Only when you want to respond * to moves of the container to do something special, or disable one of the features the * container normally has (like clipping). Use the default constructor in those cases. * @param model the custom model to be used for maintaining the list of children. */ explicit KoShapeContainer(KoShapeContainerModel *model = 0); /** * Destructor for the shape container. * All children will be orphaned by calling a KoShape::setParent(0) */ ~KoShapeContainer() override; /** * Add a child to this container. * * This container will NOT take over ownership of the shape. The caller or those creating * the shape is responsible to delete it if not needed any longer. * * @param shape the child to be managed in the container. */ void addShape(KoShape *shape); /** * Remove a child to be completely separated from the container. * * The shape will only be removed from this container but not be deleted. * * @param shape the child to be removed. */ void removeShape(KoShape *shape); /** * Return the current number of children registered. * @return the current number of children registered. */ int shapeCount() const; /** * Set the argument child to have its 'clipping' property set. * * A shape that is clipped by the container will have its visible portion * limited to the area where it intersects with the container. * If a shape is positioned or sized such that it would be painted outside * of the KoShape::outline() of its parent container, setting this property * to true will clip the shape painting to the container outline. * * @param child the child for which the property will be changed. * @param clipping the property */ void setClipped(const KoShape *child, bool clipping); /** * Returns if the argument child has its 'clipping' property set. * * A shape that is clipped by the container will have its visible portion * limited to the area where it intersects with the container. * If a shape is positioned or sized such that it would be painted outside * of the KoShape::outline() of its parent container, setting this property * to true will clip the shape painting to the container outline. * * @return if the argument child has its 'clipping' property set. * @param child the child for which the property will be returned. */ bool isClipped(const KoShape *child) const; /** * Set the shape to inherit the container transform. * * A shape that inherits the transform of the parent container will have its * share / rotation / skew etc be calculated as being the product of both its * own local transformation and also that of its parent container. * If you set this to true and rotate the container, the shape will get that * rotation as well automatically. * * @param shape the shape for which the property will be changed. * @param inherit the new value */ void setInheritsTransform(const KoShape *shape, bool inherit); /** * Returns if the shape inherits the container transform. * * A shape that inherits the transform of the parent container will have its * share / rotation / skew etc be calculated as being the product of both its * own local transformation and also that of its parent container. * If you set this to true and rotate the container, the shape will get that * rotation as well automatically. * * @return if the argument shape has its 'inherits transform' property set. * @param shape the shape for which the property will be returned. */ bool inheritsTransform(const KoShape *shape) const; /// reimplemented void paint(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintcontext) override; /** * @brief Paint the component * Implement this method to allow the shape to paint itself, just like the KoShape::paint() * method does. * * @param painter used for painting the shape * @param converter to convert between internal and view coordinates. + * @param paintcontext the painting context * @see applyConversion() */ virtual void paintComponent(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintcontext) = 0; using KoShape::update; /// reimplemented void update() const override; /** * Return the list of all child shapes. * @return the list of all child shapes */ QList shapes() const; /** * return the model for this container */ KoShapeContainerModel *model() const; /** * A special interface for KoShape to use during setParent call. Don't use * these method directly for managing shapes hierarchy! Use shape->setParent() * instead. */ struct ShapeInterface { ShapeInterface(KoShapeContainer *_q); /** * Add a child to this container. * * This container will NOT take over ownership of the shape. The caller or those creating * the shape is responsible to delete it if not needed any longer. * * @param shape the child to be managed in the container. */ void addShape(KoShape *shape); /** * Remove a child to be completely separated from the container. * * The shape will only be removed from this container but not be deleted. * * @param shape the child to be removed. */ void removeShape(KoShape *shape); protected: KoShapeContainer *q; }; ShapeInterface* shapeInterface(); protected: /** * This hook is for inheriting classes that need to do something on adding/removing * of children. * This method will be called just after the child has been added/removed. * The default implementation is empty. */ virtual void shapeCountChanged() { } void shapeChanged(ChangeType type, KoShape *shape = 0) override; /// constructor KoShapeContainer(KoShapeContainerPrivate *); private: Q_DECLARE_PRIVATE(KoShapeContainer) }; #endif diff --git a/libs/flake/KoShapeController.h b/libs/flake/KoShapeController.h index cde79865e5..9e60ff550a 100644 --- a/libs/flake/KoShapeController.h +++ b/libs/flake/KoShapeController.h @@ -1,170 +1,173 @@ /* This file is part of the KDE project * * Copyright (C) 2006-2007, 2010 Thomas Zander * Copyright (C) 2006-2008 Thorsten Zachmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOSHAPECONTROLLER_H #define KOSHAPECONTROLLER_H #include "kritaflake_export.h" #include #include #include class KoCanvasBase; class KoShape; class KoShapeContainer; class KoShapeControllerBase; class KUndo2Command; class KoDocumentResourceManager; /** * Class used by tools to maintain the list of shapes. * All applications have some sort of list of all shapes that belong to the document. * The applications implement the KoShapeControllerBase interface (all pure virtuals) * to add and remove shapes from the document. To ensure that an application can expect * a certain protocol to be adhered to when adding/removing shapes, all tools use the API * from this class for maintaining the list of shapes in the document. So no tool gets * to access the application directly. */ class KRITAFLAKE_EXPORT KoShapeController : public QObject { Q_OBJECT public: /** * Create a new Controller; typically not called by applications, only * by the KonCanvasBase constructor. * @param canvas the canvas this controller works for. The canvas can be 0 * @param shapeController the application provided shapeController that we can call. */ KoShapeController(KoCanvasBase *canvas, KoShapeControllerBase *shapeController); /// destructor ~KoShapeController() override; /** * @brief reset sets the canvas and shapebased document to 0. */ void reset(); /** * @brief Add a shape to the document. * If the shape has no parent, the active layer will become its parent. * * @param shape to add to the document + * @param parentShape the parent shape * @param parent the parent command if the resulting command is a compound undo command. * * @return command which will insert the shape into the document or 0 if the * insertion was cancelled. The command is not yet executed. */ KUndo2Command* addShape(KoShape *shape, KoShapeContainer *parentShape, KUndo2Command *parent = 0); /** * @brief Add a shape to the document, skipping any dialogs or other user interaction. * * @param shape to add to the document + * @param parentShape the parent shape * @param parent the parent command if the resulting command is a compound undo command. * * @return command which will insert the shape into the document. The command is not yet executed. */ KUndo2Command* addShapeDirect(KoShape *shape, KoShapeContainer *parentShape, KUndo2Command *parent = 0); /** * @brief Add shapes to the document, skipping any dialogs or other user interaction. * - * @param shapes to add to the document + * @param shape the shape to add to the document + * @param parentShape the parent shape * @param parent the parent command if the resulting command is a compound undo command. * * @return command which will insert the shapes into the document. The command is not yet executed. */ KUndo2Command* addShapesDirect(const QList shape, KoShapeContainer *parentShape, KUndo2Command *parent = 0); /** * @brief Remove a shape from the document. * * @param shape to remove from the document * @param parent the parent command if the resulting command is a compound undo command. * * @return command which will remove the shape from the document. * The command is not yet executed. */ KUndo2Command* removeShape(KoShape *shape, KUndo2Command *parent = 0); /** * Remove a shape from the document. * * @param shapes the set of shapes to remove from the document * @param parent the parent command if the resulting command is a compound undo command. * * @return command which will remove the shape from the document. * The command is not yet executed. */ KUndo2Command* removeShapes(const QList &shapes, KUndo2Command *parent = 0); /** * @brief Set the KoShapeControllerBase used to add/remove shapes. * * NOTE: only Sheets uses this method. Do not use it in your application. Sheets * has to also call: * KoToolManager::instance()->updateShapeControllerBase(shapeController, canvas->canvasController()); * * @param shapeController the new shapeController. */ void setShapeControllerBase(KoShapeControllerBase *shapeController); /** * The size of the document measured in rasterized pixels. This information is needed for loading * SVG documents that use 'px' as the default unit. */ QRectF documentRectInPixels() const; /** * Resolution of the rasterized representation of the document. Used to load SVG documents correctly. */ qreal pixelsPerInch() const; /** * Document rect measured in 'pt' */ QRectF documentRect() const; /** * Return a pointer to the resource manager associated with the * shape-set (typically a document). The resource manager contains * document wide resources * such as variable managers, the image * collection and others. */ KoDocumentResourceManager *resourceManager() const; /** * @brief Returns the KoShapeControllerBase used to add/remove shapes. * * @return the KoShapeControllerBase */ KoShapeControllerBase *documentBase() const; private: class Private; Private * const d; }; Q_DECLARE_METATYPE(KoShapeController *) #endif diff --git a/libs/flake/KoShapeControllerBase.h b/libs/flake/KoShapeControllerBase.h index c11dc0b4be..f14eee34a5 100644 --- a/libs/flake/KoShapeControllerBase.h +++ b/libs/flake/KoShapeControllerBase.h @@ -1,110 +1,110 @@ /* This file is part of the KDE project Copyright (C) 2006 Jan Hambrecht Copyright (C) 2006, 2010 Thomas Zander Copyright (C) 2008 C. Boemann This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOshapeControllerBASE_H #define KOshapeControllerBASE_H #include "kritaflake_export.h" #include class QRectF; class KoShape; class KoshapeControllerBasePrivate; class KoDocumentResourceManager; class KUndo2Command; /** * The KoshapeControllerBase is an abstract interface that the application's class * that owns the shapes should implement. This tends to be the document. * @see KoShapeDeleteCommand, KoShapeCreateCommand */ class KRITAFLAKE_EXPORT KoShapeControllerBase { public: KoShapeControllerBase(); virtual ~KoShapeControllerBase(); /** * Add a shape to the shape controller, allowing it to be seen and saved. * The controller should add the shape to the ShapeManager instance(s) manually * if the shape is one that should be currently shown on screen. * @param shape the new shape */ void addShape(KoShape *shape); /** * Add shapes to the shape controller, allowing it to be seen and saved. * The controller should add the shape to the ShapeManager instance(s) manually * if the shape is one that should be currently shown on screen. - * @param shape the new shape + * @param shapes the shapes to add */ virtual void addShapes(const QList shapes) = 0; /** * Remove a shape from the shape controllers control, allowing it to be deleted shortly after * The controller should remove the shape from all the ShapeManager instance(s) manually * @param shape the shape to remove */ virtual void removeShape(KoShape *shape) = 0; /** * This method gets called after the KoShapeDeleteCommand is executed * * This passes the KoShapeDeleteCommand as the command parameter. This makes it possible * for applications that need to do something after the KoShapeDeleteCommand is done, e.g. * adding one commands that need to be executed when a shape was deleted. * The default implementation is empty. * @param shapes The list of shapes that got removed. * @param command The command that was used to remove the shapes from the document. */ virtual void shapesRemoved(const QList &shapes, KUndo2Command *command); /** * Return a pointer to the resource manager associated with the * shape-set (typically a document). The resource manager contains * document wide resources * such as variable managers, the image * collection and others. */ virtual KoDocumentResourceManager *resourceManager() const; /** * The size of the document measured in rasterized pixels. This information is needed for loading * SVG documents that use 'px' as the default unit. */ virtual QRectF documentRectInPixels() const = 0; /** * The size of the document measured in 'pt' */ QRectF documentRect() const; /** * Resolution of the rasterized representation of the document. Used to load SVG documents correctly. */ virtual qreal pixelsPerInch() const = 0; private: KoshapeControllerBasePrivate * const d; }; #endif diff --git a/libs/flake/KoShapeManager.h b/libs/flake/KoShapeManager.h index 8b9600658d..9b21d5af37 100644 --- a/libs/flake/KoShapeManager.h +++ b/libs/flake/KoShapeManager.h @@ -1,212 +1,214 @@ /* This file is part of the KDE project Copyright (C) 2006-2008 Thorsten Zachmann Copyright (C) 2007, 2009 Thomas Zander This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOSHAPEMANAGER_H #define KOSHAPEMANAGER_H #include #include #include #include "KoFlake.h" #include "kritaflake_export.h" class KoShape; class KoSelection; class KoViewConverter; class KoCanvasBase; class KoPointerEvent; class KoShapePaintingContext; class QPainter; class QPointF; class QRectF; /** * The shape manager hold a list of all shape which are in scope. * There is one shape manager per canvas. This makes the shape manager * different from QGraphicsScene, which contains the datamodel for all * graphics items: KoShapeManager only contains the subset of shapes * that are shown in its canvas. * * The selection in the different views can be different. */ class KRITAFLAKE_EXPORT KoShapeManager : public QObject { Q_OBJECT public: /// enum for add() enum Repaint { PaintShapeOnAdd, ///< Causes each shapes 'update()' to be called after being added to the shapeManager AddWithoutRepaint ///< Avoids each shapes 'update()' to be called for faster addition when its possible. }; /** * Constructor. */ explicit KoShapeManager(KoCanvasBase *canvas); /** * Constructor that takes a list of shapes, convenience version. * @param shapes the shapes to start out with, see also setShapes() * @param canvas the canvas this shape manager is working on. */ KoShapeManager(KoCanvasBase *canvas, const QList &shapes); ~KoShapeManager() override; /** * Remove all previously owned shapes and make the argument list the new shapes * to be managed by this manager. * @param shapes the new shapes to manage. * @param repaint if true it will trigger a repaint of the shapes */ void setShapes(const QList &shapes, Repaint repaint = PaintShapeOnAdd); /// returns the list of maintained shapes QList shapes() const; /** * Get a list of all shapes that don't have a parent. */ QList topLevelShapes() const; public Q_SLOTS: /** * Add a KoShape to be displayed and managed by this manager. * This will trigger a repaint of the shape. * @param shape the shape to add * @param repaint if true it will trigger a repaint of the shape */ void addShape(KoShape *shape, KoShapeManager::Repaint repaint = PaintShapeOnAdd); /** * Remove a KoShape from this manager * @param shape the shape to remove */ void remove(KoShape *shape); public: /// return the selection shapes for this shapeManager KoSelection *selection() const; /** * Paint all shapes and their selection handles etc. * @param painter the painter to paint to. * @param forPrint if true, make sure only actual content is drawn and no decorations. * @param converter to convert between document and view coordinates. */ void paint(QPainter &painter, const KoViewConverter &converter, bool forPrint); /** * Returns the shape located at a specific point in the document. * If more than one shape is located at the specific point, the given selection type * controls which of them is returned. * @param position the position in the document coordinate system. * @param selection controls which shape is returned when more than one shape is at the specific point * @param omitHiddenShapes if true, only visible shapes are considered */ KoShape *shapeAt(const QPointF &position, KoFlake::ShapeSelection selection = KoFlake::ShapeOnTop, bool omitHiddenShapes = true); /** * Returns the shapes which intersects the specific rect in the document. * @param rect the rectangle in the document coordinate system. - * @param omitHiddenShapes if true, only visible shapes are considered + * @param omitHiddenShapes if @c true, only visible shapes are considered + * @param containedMode if @c true use contained mode */ QList shapesAt(const QRectF &rect, bool omitHiddenShapes = true, bool containedMode = false); /** * Request a repaint to be queued. * The repaint will be restricted to the parameters rectangle, which is expected to be * in points (the document coordinates system of KoShape) and it is expected to be * normalized and based in the global coordinates, not any local coordinates. *

This method will return immediately and only request a repaint. Successive calls * will be merged into an appropriate repaint action. * @param rect the rectangle (in pt) to queue for repaint. * @param shape the shape that is going to be redrawn; only needed when selectionHandles=true * @param selectionHandles if true; find out if the shape is selected and repaint its * selection handles at the same time. */ void update(const QRectF &rect, const KoShape *shape = 0, bool selectionHandles = false); /** * Update the tree for finding the shapes. * This will remove the shape from the tree and will reinsert it again. * The update to the tree will be posponed until it is needed so that successive calls * will be merged into one. * @param shape the shape to updated its position in the tree. */ void notifyShapeChanged(KoShape *shape); /** * Paint a shape * * @param shape the shape to paint * @param painter the painter to paint to. * @param converter to convert between document and view coordinates. + * @param paintContext the painting context */ static void paintShape(KoShape *shape, QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintContext); /** * @brief renderSingleShape renders a shape on \p painter. This method includes all the * needed steps for painting a single shape: setting transformations, clipping and masking. */ static void renderSingleShape(KoShape *shape, QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintContext); /** * A special interface for KoShape to use during shape destruction. Don't use this * interface directly unless you are KoShape. */ struct ShapeInterface { ShapeInterface(KoShapeManager *_q); /** * Called by a shape when it is destructed. Please note that you cannot access * any shape's method type or information during this call because the shape might be * semi-destroyed. */ void notifyShapeDestructed(KoShape *shape); protected: KoShapeManager *q; }; ShapeInterface* shapeInterface(); Q_SIGNALS: /// emitted when the selection is changed void selectionChanged(); /// emitted when an object in the selection is changed (moved/rotated etc) void selectionContentChanged(); /// emitted when any object changed (moved/rotated etc) void contentChanged(); private: KoCanvasBase *canvas(); class Private; Private * const d; Q_PRIVATE_SLOT(d, void updateTree()) }; #endif diff --git a/libs/flake/KoToolManager.h b/libs/flake/KoToolManager.h index f99dc52d34..77dbe4edd1 100644 --- a/libs/flake/KoToolManager.h +++ b/libs/flake/KoToolManager.h @@ -1,335 +1,335 @@ /* This file is part of the KDE project * Copyright (c) 2005-2006 Boudewijn Rempt * Copyright (C) 2006, 2008 Thomas Zander * Copyright (C) 2006 Thorsten Zachmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KO_TOOL_MANAGER #define KO_TOOL_MANAGER #include "KoInputDevice.h" #include "kritaflake_export.h" #include #include class KoCanvasController; class KoShapeControllerBase; class KoToolFactoryBase; class KoCanvasBase; class KoToolBase; class KoCreateShapesTool; class KActionCollection; class KoShape; class KoInputDeviceHandlerEvent; class KoShapeLayer; class ToolHelper; class QKeySequence; class QCursor; /** * This class serves as a QAction-like control object for activation of a tool. * * It allows to implement a custom UI to control the activation of tools. * See KoToolBox & KoModeBox in the kowidgets library. * * KoToolAction objects are indirectly owned by the KoToolManager singleton * and live until the end of its lifetime. */ class KRITAFLAKE_EXPORT KoToolAction : public QObject { Q_OBJECT public: // toolHelper takes over ownership, and those live till the end of KoToolManager. explicit KoToolAction(ToolHelper *toolHelper); ~KoToolAction() override; public: QString id() const; ///< The id of the tool QString iconText() const; ///< The icontext of the tool QString toolTip() const; ///< The tooltip of the tool QString iconName() const; ///< The icon name of the tool QKeySequence shortcut() const; ///< The shortcut to activate the tool QString section() const; ///< The section the tool wants to be in. int priority() const; ///< Lower number (higher priority) means coming first in the section. int buttonGroupId() const; ///< A unique ID for this tool as passed by changedTool(), >= 0 QString visibilityCode() const; ///< This tool should become visible when we emit this string in toolCodesSelected() public Q_SLOTS: void trigger(); ///< Request the activation of the tool Q_SIGNALS: void changed(); ///< Emitted when a property changes (shortcut ATM) private: friend class ToolHelper; class Private; Private *const d; }; /** * This class manages the activation and deactivation of tools for * each input device. * * Managing the active tool and switching tool based on various variables. * * The state of the toolbox will be the same for all views in the process so practically * you can say we have one toolbox per application instance (process). Implementation * does not allow one widget to be in more then one view, so we just make sure the toolbox * is hidden in not-in-focus views. * * The ToolManager is a singleton and will manage all views in all applications that * are loaded in this process. This means you will have to register and unregister your view. * When creating your new view you should use a KoCanvasController() and register that * with the ToolManager like this: @code MyGuiWidget::MyGuiWidget() { m_canvasController = new KoCanvasController(this); m_canvasController->setCanvas(m_canvas); KoToolManager::instance()->addControllers(m_canvasController)); } MyGuiWidget::~MyGuiWidget() { KoToolManager::instance()->removeCanvasController(m_canvasController); } @endcode * * For a new view that extends KoView all you need to do is implement KoView::createToolBox() * * KoToolManager also keeps track of the current tool based on a complex set of conditions and heuristics: - there is one active tool per KoCanvasController (and there is one KoCanvasController per view, because this is a class with scrollbars and a zoomlevel and so on) - for every pointing device (determined by the unique id of tablet, or 0 for mice -- you may have more than one mouse attached, but Qt cannot distinguish between them, there is an associated tool. - depending on things like tablet leave/enter proximity, incoming mouse or tablet events and a little timer (that gets stopped when we know what is what), the active pointing device is determined, and the active tool is set accordingly. Nota bene: if you use KoToolManager and register your canvases with it you no longer have to manually implement methods to route mouse, tablet, key or wheel events to the active tool. In fact, it's no longer interesting to you which tool is active; you can safely route the paint event through KoToolProxy::paint(). (The reason the input events are handled completely by the toolmanager and the paint events not is that, generally speaking, it's okay if the tools get the input events first, but you want to paint your shapes or other canvas stuff first and only then paint the tool stuff.) */ class KRITAFLAKE_EXPORT KoToolManager : public QObject { Q_OBJECT public: KoToolManager(); /// Return the toolmanager singleton static KoToolManager* instance(); ~KoToolManager() override; /** * Register actions for switching to tools at the actionCollection parameter. * The actions will have the text / shortcut as stated by the toolFactory. * If the application calls this in their KoView extending class they will have all the benefits * from allowing this in the menus and to allow the use to configure the shortcuts used. * @param ac the actionCollection that will be the parent of the actions. * @param controller tools registered with this controller will have all their actions added as well. */ void registerToolActions(KActionCollection *ac, KoCanvasController *controller); /** * Register a new canvas controller * @param controller the view controller that this toolmanager will manage the tools for */ void addController(KoCanvasController *controller); /** * Remove a set of controllers * When the controller is no longer used it should be removed so all tools can be * deleted and stop eating memory. * @param controller the controller that is removed */ void removeCanvasController(KoCanvasController *controller); /** * Attempt to remove a controller. * This is automatically called when a controller's proxy object is deleted, and * it ensures that the controller is, in fact, removed, even if the creator forgot * to do so. * @param controller the proxy object of the controller to be removed */ Q_SLOT void attemptCanvasControllerRemoval(QObject *controller); /// @return the active canvas controller KoCanvasController *activeCanvasController() const; /** * Return the tool that is able to create shapes for this param canvas. * This is typically used by the KoShapeSelector to set which shape to create next. * @param canvas the canvas that is a child of a previously registered controller * who's tool you want. * @see addController() */ KoCreateShapesTool *shapeCreatorTool(KoCanvasBase *canvas) const; /** * Returns the tool for the given tool id. The tool may be 0 * @param canvas the canvas that is a child of a previously registered controller * who's tool you want. + * @param id the tool identifier * @see addController() */ KoToolBase *toolById(KoCanvasBase *canvas, const QString &id) const; /// @return the currently active pointing device KoInputDevice currentInputDevice() const; /** * For the list of shapes find out which tool is the highest priority tool that can handle it. * @returns the toolId for the shapes. * @param shapes a list of shapes, a selection for example, that is used to look for the tool. */ QString preferredToolForSelection(const QList &shapes); /** * Returns the list of toolActions for the current tools. * @returns lists of toolActions for the current tools. */ QList toolActionList() const; /// Request tool activation for the given canvas controller void requestToolActivation(KoCanvasController *controller); /// Returns the toolId of the currently active tool QString activeToolId() const; void initializeCurrentToolForCanvas(); class Private; /** * \internal return the private object for the toolmanager. */ KoToolManager::Private *priv(); public Q_SLOTS: /** * Request switching tool * @param id the id of the tool */ void switchToolRequested(const QString &id); /** * Request change input device * @param id the id of the input device */ void switchInputDeviceRequested(const KoInputDevice &id); /** * Request for temporary switching the tools. * This switch can be later reverted with switchBackRequested(). * @param id the id of the tool * * @see switchBackRequested() */ void switchToolTemporaryRequested(const QString &id); /** * Switches back to the original tool after the temporary switch * has been done. It the user changed the tool manually on the way, * then it switches to the interaction tool */ void switchBackRequested(); Q_SIGNALS: /** * Emitted when a new tool is going to override the current tool * @param canvas the currently active canvas. */ void aboutToChangeTool(KoCanvasController *canvas); /** * Emitted when a new tool was selected or became active. * @param canvas the currently active canvas. * @param uniqueToolId a random but unique code for the new tool. */ void changedTool(KoCanvasController *canvas, int uniqueToolId); /** * Emitted after the selection changed to state which unique shape-types are now * in the selection. - * @param canvas the currently active canvas. * @param types a list of string that are the shape types of the selected objects. */ void toolCodesSelected(const QList &types); /** * Emitted after the current layer changed either its properties or to a new layer. * @param canvas the currently active canvas. * @param layer the layer that is selected. */ void currentLayerChanged(const KoCanvasController *canvas, const KoShapeLayer *layer); /** * Every time a new input device gets used by a tool, this event is emitted. * @param device the new input device that the user picked up. */ void inputDeviceChanged(const KoInputDevice &device); /** * Emitted whenever the active canvas changed. * @param canvas the new activated canvas (might be 0) */ void changedCanvas(const KoCanvasBase *canvas); /** * Emitted whenever the active tool changes the status text. * @param statusText the new status text */ void changedStatusText(const QString &statusText); /** * emitted whenever a new tool is dynamically added for the given canvas */ void addedTool(KoToolAction *toolAction, KoCanvasController *canvas); /** * Emit the new tool option widgets to be used with this canvas. */ void toolOptionWidgetsChanged(KoCanvasController *controller, const QList > &widgets); private: KoToolManager(const KoToolManager&); KoToolManager operator=(const KoToolManager&); Q_PRIVATE_SLOT(d, void toolActivated(ToolHelper *tool)) Q_PRIVATE_SLOT(d, void detachCanvas(KoCanvasController *controller)) Q_PRIVATE_SLOT(d, void attachCanvas(KoCanvasController *controller)) Q_PRIVATE_SLOT(d, void movedFocus(QWidget *from, QWidget *to)) Q_PRIVATE_SLOT(d, void updateCursor(const QCursor &cursor)) Q_PRIVATE_SLOT(d, void selectionChanged(const QList &shapes)) Q_PRIVATE_SLOT(d, void currentLayerChanged(const KoShapeLayer *layer)) QPair createTools(KoCanvasController *controller, ToolHelper *tool); Private *const d; }; #endif diff --git a/libs/flake/commands/KoPathBaseCommand.h b/libs/flake/commands/KoPathBaseCommand.h index 25b23acc8d..ee40b5110d 100644 --- a/libs/flake/commands/KoPathBaseCommand.h +++ b/libs/flake/commands/KoPathBaseCommand.h @@ -1,53 +1,54 @@ /* This file is part of the KDE project * Copyright (C) 2006 Jan Hambrecht * Copyright (C) 2006,2007 Thorsten Zachmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOPATHBASECOMMAND_H #define KOPATHBASECOMMAND_H #include #include class KoPathShape; /// the base command for commands altering a path shape class KoPathBaseCommand : public KUndo2Command { public: /** * @param parent the parent command used for macro commands */ explicit KoPathBaseCommand(KUndo2Command *parent = 0); /** initialize the base command with a single shape + * @param shape the shape * @param parent the parent command used for macro commands */ explicit KoPathBaseCommand(KoPathShape *shape, KUndo2Command *parent = 0); protected: /** * Schedules repainting of all shapes control point rects. * @param normalizeShapes controls if paths are normalized before painting */ void repaint(bool normalizeShapes); QSet m_shapes; ///< the shapes the command operates on }; #endif // KOPATHBASECOMMAND_H diff --git a/libs/flake/commands/KoPathControlPointMoveCommand.h b/libs/flake/commands/KoPathControlPointMoveCommand.h index e1d14381ba..12e8848e90 100644 --- a/libs/flake/commands/KoPathControlPointMoveCommand.h +++ b/libs/flake/commands/KoPathControlPointMoveCommand.h @@ -1,58 +1,59 @@ /* This file is part of the KDE project * Copyright (C) 2006 Jan Hambrecht * Copyright (C) 2006,2007 Thorsten Zachmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOPATHCONTROLPOINTMOVECOMMAND_H #define KOPATHCONTROLPOINTMOVECOMMAND_H #include #include #include "KoPathPointData.h" #include "KoPathPoint.h" #include "kritaflake_export.h" /// The undo / redo command for path point moving. class KRITAFLAKE_EXPORT KoPathControlPointMoveCommand : public KUndo2Command { public: /** * Command to move one control path point. + * @param pointData the data of the point to move * @param offset the offset by which the point is moved in document coordinates * @param pointType the type of the point to move * @param parent the parent command used for macro commands */ KoPathControlPointMoveCommand(const KoPathPointData &pointData, const QPointF &offset, KoPathPoint::PointType pointType, KUndo2Command *parent = 0); /// redo the command void redo() override; /// revert the actions done in redo void undo() override; int id() const override; bool mergeWith(const KUndo2Command *command) override; private: KoPathPointData m_pointData; // the offset in shape coordinates QPointF m_offset; KoPathPoint::PointType m_pointType; }; #endif // KOPATHCONTROLPOINTMOVECOMMAND_H diff --git a/libs/flake/commands/KoShapeGroupCommand.h b/libs/flake/commands/KoShapeGroupCommand.h index 8d70cbc4e6..a18f8886a5 100644 --- a/libs/flake/commands/KoShapeGroupCommand.h +++ b/libs/flake/commands/KoShapeGroupCommand.h @@ -1,83 +1,80 @@ /* This file is part of the KDE project * Copyright (C) 2006,2010 Thomas Zander * Copyright (C) 2007 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOSHAPEGROUPCOMMAND_H #define KOSHAPEGROUPCOMMAND_H #include "kritaflake_export.h" #include #include #include class KoShape; class KoShapeGroup; class KoShapeContainer; class KoShapeGroupCommandPrivate; /// The undo / redo command for grouping shapes class KRITAFLAKE_EXPORT KoShapeGroupCommand : public KUndo2Command { public: /** * Create command to group a set of shapes into a predefined container. * This uses the KoShapeGroupCommand(KoShapeGroup *container, const QList &shapes, KUndo2Command *parent = 0); * constructor. * The createCommand will make sure that the group will have the z-index and the parent of the top most shape in the group. * * @param container the group to group the shapes under. - * @param parent the parent command if the resulting command is a compound undo command. * @param shapes a list of all the shapes that should be grouped. + * @param shouldNormalize whether the shapes should be normalized */ static KoShapeGroupCommand *createCommand(KoShapeContainer *container, const QList &shapes, bool shouldNormalize = false); /** * Command to group a set of shapes into a predefined container. * @param container the container to group the shapes under. * @param shapes a list of all the shapes that should be grouped. - * @param clipped shows whether the shapes should be clipped by the container - * See KoShapeContainer::isClipped() - * @param inheritTransform shows whether the shapes should inherit the parent transformation - * See KoShapeContainer::inheritsTransform() + * @param shouldNormalize shows whether the shapes should be normalized by the container * @param parent the parent command used for macro commands */ KoShapeGroupCommand(KoShapeContainer *container, const QList &shapes, bool shouldNormalize, KUndo2Command *parent = 0); /** * Command to group a set of shapes into a predefined container. * Convenience constructor since KoShapeGroup does not allow clipping. * @param container the group to group the shapes under. * @param parent the parent command if the resulting command is a compound undo command. * @param shapes a list of all the shapes that should be grouped. */ KoShapeGroupCommand(KoShapeContainer *container, const QList &shapes, KUndo2Command *parent = 0); ~KoShapeGroupCommand() override; /// redo the command void redo() override; /// revert the actions done in redo void undo() override; protected: const QScopedPointer d; }; #endif diff --git a/libs/flake/commands/KoShapeReorderCommand.h b/libs/flake/commands/KoShapeReorderCommand.h index ac640a31f2..1643052096 100644 --- a/libs/flake/commands/KoShapeReorderCommand.h +++ b/libs/flake/commands/KoShapeReorderCommand.h @@ -1,130 +1,132 @@ /* This file is part of the KDE project * Copyright (C) 2006 Thomas Zander * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOSHAPEREORDERCOMMAND_H #define KOSHAPEREORDERCOMMAND_H #include "kritaflake_export.h" #include #include #include class KoShape; class KoShapeManager; class KoShapeReorderCommandPrivate; /// This command allows you to change the zIndex of a number of shapes. class KRITAFLAKE_EXPORT KoShapeReorderCommand : public KUndo2Command { public: struct KRITAFLAKE_EXPORT IndexedShape : boost::less_than_comparable { IndexedShape(); IndexedShape(KoShape *_shape); bool operator<(const IndexedShape &rhs) const; int zIndex = 0; KoShape *shape = 0; }; public: /** * Constructor. * @param shapes the set of objects that are moved. * @param newIndexes the new indexes for the shapes. * this list naturally must have the same amount of items as the shapes set. * @param parent the parent command used for macro commands */ KoShapeReorderCommand(const QList &shapes, QList &newIndexes, KUndo2Command *parent = 0); KoShapeReorderCommand(const QList &shapes, KUndo2Command *parent = 0); ~KoShapeReorderCommand() override; /// An enum for defining what kind of reordering to use. enum MoveShapeType { RaiseShape, ///< raise the selected shape to the level that it is above the shape that is on top of it. LowerShape, ///< Lower the selected shape to the level that it is below the shape that is below it. BringToFront, ///< Raise the selected shape to be on top of all shapes. SendToBack ///< Lower the selected shape to be below all other shapes. }; /** * Create a new KoShapeReorderCommand by calculating the new indexes required to move the shapes * according to the move parameter. * @param shapes all the shapes that should be moved. * @param manager the shapeManager that contains all the shapes that could have their indexes changed. * @param move the moving type. * @param parent the parent command for grouping purposes. * @return command for reordering the shapes or 0 if no reordering happened */ static KoShapeReorderCommand *createCommand(const QList &shapes, KoShapeManager *manager, MoveShapeType move, KUndo2Command *parent = 0); /** * @brief mergeInShape adjust zIndex of all the \p shapes and \p newShape to * avoid collisions between \p shapes and \p newShape. * * Note1: \p newShape may or may not be contained in \p shapes, there * is no difference. * Note2: the collisions inside \p shapes are ignored. They are just * adjusted to avoid collisions with \p newShape only + * @param shapes list of shapes + * @param newShape the new shape * @param parent the parent command for grouping purposes. * @return command for reordering the shapes or 0 if no reordering happened */ static KoShapeReorderCommand *mergeInShape(QList shapes, KoShape *newShape, KUndo2Command *parent = 0); /** * Recalculates the attached z-indexes of \p shapes so that all indexes go * strictly in ascending order and no shapes have repetitive indexes. The * physical order of the shapes in the array is not changed, on the indexes * in IndexedShape are corrected. */ static QList homogenizeZIndexes(QList shapes); /** * Convenience version of homogenizeZIndexes() that removes all the IndexedShape * objects, which z-index didn't change during homogenization. In a result * you get a list that can be passed to KoShapeReorderCommand directly. */ static QList homogenizeZIndexesLazy(QList shapes); /** * Put all the shapes in \p shapesAbove above the shapes in \p shapesBelow, adjusting their * z-index values. */ static QList mergeDownShapes(QList shapesBelow, QList shapesAbove); /// redo the command void redo() override; /// revert the actions done in redo void undo() override; private: KoShapeReorderCommandPrivate * const d; }; KRITAFLAKE_EXPORT QDebug operator<<(QDebug dbg, const KoShapeReorderCommand::IndexedShape &indexedShape); #endif diff --git a/libs/flake/commands/KoShapeUngroupCommand.h b/libs/flake/commands/KoShapeUngroupCommand.h index 098cbcd6b1..2dca24cf05 100644 --- a/libs/flake/commands/KoShapeUngroupCommand.h +++ b/libs/flake/commands/KoShapeUngroupCommand.h @@ -1,57 +1,58 @@ /* This file is part of the KDE project * Copyright (C) 2006 Thomas Zander * Copyright (C) 2006 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOSHAPEUNGROUPCOMMAND_H #define KOSHAPEUNGROUPCOMMAND_H #include "kritaflake_export.h" #include #include class KoShape; class KoShapeGroup; class KoShapeContainer; /// The undo / redo command for ungrouping shapes class KRITAFLAKE_EXPORT KoShapeUngroupCommand : public KUndo2Command { public: /** * Command to ungroup a set of shapes from one parent container. * @param container the group to ungroup the shapes from. * @param shapes a list of all the shapes that should be ungrouped. + * @param topLevelShapes a list of top level shapes. * @param parent the parent command used for macro commands */ KoShapeUngroupCommand(KoShapeContainer *container, const QList &shapes, const QList &topLevelShapes = QList(), KUndo2Command *parent = 0); ~KoShapeUngroupCommand(); /// redo the command void redo() override; /// revert the actions done in redo void undo() override; private: struct Private; const QScopedPointer m_d; }; #endif diff --git a/libs/flake/svg/SvgUtil.h b/libs/flake/svg/SvgUtil.h index 22493ca9c2..b72018261e 100644 --- a/libs/flake/svg/SvgUtil.h +++ b/libs/flake/svg/SvgUtil.h @@ -1,150 +1,150 @@ /* This file is part of the KDE project * Copyright (C) 2009 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef SVGUTIL_H #define SVGUTIL_H #include "kritaflake_export.h" #include class QString; class QTransform; class QStringList; class KoXmlWriter; #include class SvgGraphicsContext; class KRITAFLAKE_EXPORT SvgUtil { public: // remove later! pixels *are* user coordinates static double fromUserSpace(double value); static double toUserSpace(double value); static double ptToPx(SvgGraphicsContext *gc, double value); /// Converts given point from points to userspace units. static QPointF toUserSpace(const QPointF &point); /// Converts given rectangle from points to userspace units. static QRectF toUserSpace(const QRectF &rect); /// Converts given rectangle from points to userspace units. static QSizeF toUserSpace(const QSizeF &size); /** * Parses the given string containing a percentage number. - * @param s the input string containing the percentage + * @param value the input number containing the percentage * @return the percentage number normalized to 0..100 */ static QString toPercentage(qreal value); /** * Parses the given string containing a percentage number. * @param s the input string containing the percentage * @return the percentage number normalized to 0..1 */ static double fromPercentage(QString s); /** * Converts position from objectBoundingBox units to userSpace units. */ static QPointF objectToUserSpace(const QPointF &position, const QRectF &objectBound); /** * Converts size from objectBoundingBox units to userSpace units. */ static QSizeF objectToUserSpace(const QSizeF &size, const QRectF &objectBound); /** * Converts position from userSpace units to objectBoundingBox units. */ static QPointF userSpaceToObject(const QPointF &position, const QRectF &objectBound); /** * Converts size from userSpace units to objectBoundingBox units. */ static QSizeF userSpaceToObject(const QSizeF &size, const QRectF &objectBound); /// Converts specified transformation to a string static QString transformToString(const QTransform &transform); /// Writes a \p transform as an attribute \p name iff the transform is not empty static void writeTransformAttributeLazy(const QString &name, const QTransform &transform, KoXmlWriter &shapeWriter); /// Parses a viewbox attribute into an rectangle static bool parseViewBox(SvgGraphicsContext *gc, const KoXmlElement &e, const QRectF &elementBounds, QRectF *_viewRect, QTransform *_viewTransform); struct PreserveAspectRatioParser; static void parseAspectRatio(const PreserveAspectRatioParser &p, const QRectF &elementBounds, const QRectF &viewRect, QTransform *_viewTransform); /// Parses a length attribute static qreal parseUnit(SvgGraphicsContext *gc, const QString &, bool horiz = false, bool vert = false, const QRectF &bbox = QRectF()); /// parses a length attribute in x-direction static qreal parseUnitX(SvgGraphicsContext *gc, const QString &unit); /// parses a length attribute in y-direction static qreal parseUnitY(SvgGraphicsContext *gc, const QString &unit); /// parses a length attribute in xy-direction static qreal parseUnitXY(SvgGraphicsContext *gc, const QString &unit); /// parses angle, result in *radians*! static qreal parseUnitAngular(SvgGraphicsContext *gc, const QString &unit); /// parses the number into parameter number static const char * parseNumber(const char *ptr, qreal &number); static qreal parseNumber(const QString &string); static QString mapExtendedShapeTag(const QString &tagName, const KoXmlElement &element); static QStringList simplifyList(const QString &str); struct KRITAFLAKE_EXPORT PreserveAspectRatioParser { PreserveAspectRatioParser(const QString &str); enum Alignment { Min, Middle, Max }; bool defer = false; Qt::AspectRatioMode mode = Qt::IgnoreAspectRatio; Alignment xAlignment = Min; Alignment yAlignment = Min; QPointF rectAnchorPoint(const QRectF &rc) const; QString toString() const; private: Alignment alignmentFromString(const QString &str) const; QString alignmentToString(Alignment alignment) const; static qreal alignedValue(qreal min, qreal max, Alignment alignment); }; }; #endif // SVGUTIL_H diff --git a/libs/flake/text/KoSvgTextChunkShape.h b/libs/flake/text/KoSvgTextChunkShape.h index fd790df9a6..df6c966f72 100644 --- a/libs/flake/text/KoSvgTextChunkShape.h +++ b/libs/flake/text/KoSvgTextChunkShape.h @@ -1,174 +1,174 @@ /* * Copyright (c) 2017 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KOSVGTEXTCHUNKSHAPE_H #define KOSVGTEXTCHUNKSHAPE_H #include "kritaflake_export.h" #include #include class HtmlSavingContext; class KoSvgTextProperties; class KoSvgTextChunkShapePrivate; class KoSvgTextChunkShapeLayoutInterface; /** * KoSvgTextChunkShape is an elementary block of SVG text object. * - * KoSvgTextChunkShape represents either a or element of SVG. + * KoSvgTextChunkShape represents either a \ or \ element of SVG. * The chunk shape uses flake hierarchy to represent the DOM hierarchy of the * supplied text. All the attributes of text blocks can be fetched using * textProperties() method. * * KoSvgTextChunkShape uses special text properties object to overcome the * flake's "property inheritance" limitation. Basically, flake doesn't support * the inheritance of shape properties: every shape stores all the properties * that were defined at the stage of loading/creation. KoSvgTextProperties is a * wrapper that allows the user to compare the properties of the two shapes and * return only the ones that are unique for a child shape. That allows us to * generate a correct SVG/markup code that can be edited by the user easily. * * WARNING: beware the difference between "svg-text-chunk" and * KoSvgTextChunkShape! The chunk shape is **not** a "text chunk" in SVG's * definition. According to SVG, "text chunk" is a set of characters anchored to * a specific absolute position on canvas. And KoSvgTextChunkShape is just one - * or element. Obviously, one can contain multiple "text - * chunks" and, vice versa, a "text chunk" can spread onto multiple 's. + * \ or \ element. Obviously, one \ can contain multiple "text + * chunks" and, vice versa, a "text chunk" can spread onto multiple \'s. */ class KRITAFLAKE_EXPORT KoSvgTextChunkShape : public KoShapeContainer, public SvgShape { public: KoSvgTextChunkShape(); KoSvgTextChunkShape(const KoSvgTextChunkShape &rhs); ~KoSvgTextChunkShape() override; KoShape* cloneShape() const override; QSizeF size() const override; void setSize(const QSizeF &size) override; QRectF outlineRect() const override; QPainterPath outline() const override; void paintComponent(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintContext) override; void saveOdf(KoShapeSavingContext &Context) const override; bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &Context) override; bool saveHtml(HtmlSavingContext &context); /** * Reset the text shape into initial state, removing all the child shapes. * This method is used by text-updating code to upload the updated text * into shape. The uploading code first calls resetTextShape() and then adds * new children. */ virtual void resetTextShape(); bool saveSvg(SvgSavingContext &context) override; bool loadSvg(const KoXmlElement &element, SvgLoadingContext &context) override; bool loadSvgTextNode(const KoXmlText &text, SvgLoadingContext &context); /** * Normalize the SVG character transformations * * In SVG x,y,dx,dy,rotate attributes are inherited from the parent shapes * in a curious ways. We do not want to unwind the links on the fly, so we * just parse and adjust them right when the loading completed. After * normalizeCharTransformations() is finished, all the child shapes will * have local transformations set according to the parent's lists. */ void normalizeCharTransformations(); /** * Compress the inheritance of 'fill' and 'stroke'. * * The loading code makes no difference if the fill or stroke was inherited * or not. That is not a problem for normal shapes, but it cannot work for * text shapes. The text has different inheritance rules: if the parent * text chunk has a gradient fill, its inheriting descendants will * **smoothly continue** this gradient. They will not start a new gradient * in their local coordinate system. * * Therefore, after loading, the loading code calls * simplifyFillStrokeInheritance() which marks the coinciding strokes and * fills so that the rendering code will be able to distinguish them in the * future. * * Proper fill inheritance is also needed for the GUI. When the user * changes the color of the parent text chunk, all the inheriting children * should update its color automatically, without GUI recursively * traversing the shapes. * */ void simplifyFillStrokeInheritance(); /** * SVG properties of the text chunk * @return the properties object with fill and stroke included as a property */ KoSvgTextProperties textProperties() const; /** * Return the type of the chunk. * * The chunk can be either a "text chunk", that contains a text string * itself, of an "intermediate chunk" that doesn't contain any text itself, * but works as a group for a set of child chunks, which might be either * text (leaf) or intermediate chunks. Such groups are needed to define a - * common text style for a group of '' objects. + * common text style for a group of '\' objects. * * @return true if the chunk is a "text chunk" false if it is "intermediate chunk" */ bool isTextNode() const; /** * A special interface for KoSvgTextShape's layout code. Don't use it * unless you are KoSvgTextShape. */ KoSvgTextChunkShapeLayoutInterface* layoutInterface(); /** * WARNING: this propperty is available only if isRootTextNode() is true * * @return true if the shape should be edited in a rich-text editor */ bool isRichTextPreferred() const; /** * WARNING: this propperty is available only if isRootTextNode() is true * * Sets whether the shape should be edited in rich-text editor */ void setRichTextPreferred(bool value); protected: /** * Show if the shape is a root of the text hierarchy. Always true for * KoSvgTextShape and always false for KoSvgTextChunkShape */ virtual bool isRootTextNode() const; protected: KoSvgTextChunkShape(KoSvgTextChunkShapePrivate *dd); private: Q_DECLARE_PRIVATE(KoSvgTextChunkShape) }; #endif // KOSVGTEXTCHUNKSHAPE_H diff --git a/libs/flake/text/KoSvgTextProperties.h b/libs/flake/text/KoSvgTextProperties.h index 071cef7668..b0c51f5870 100644 --- a/libs/flake/text/KoSvgTextProperties.h +++ b/libs/flake/text/KoSvgTextProperties.h @@ -1,192 +1,192 @@ /* * Copyright (c) 2017 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KOSVGTEXTPROPERTIES_H #define KOSVGTEXTPROPERTIES_H #include "kritaflake_export.h" #include #include #include class SvgLoadingContext; /** * KoSvgTextProperties represents the text attributes defined in SVG DOM tree * * There is a limitation in flake: it doesn't support the inheritance of shape * properties: every shape stores all the properties that were defined at the * loading/creation stage. KoSvgTextProperties allows the user to compare * the properties of the two shapes and distinguish, which properties were * inherited by text shape, and which are its own. It is needed to generate a * correct and clean SVG/markup code that can be edited by the user easily. - * Otherwise, every block will contain the full list of 20+ attributes, + * Otherwise, every \ block will contain the full list of 20+ attributes, * which are not interesting for the user, since they are inherited or default. * * To achieve the goal, KoSvgTextProperties wraps all the SVG attributes into a * map of QVariants. When the user need to find a set of unique properties * of the shape, it iterates through the map and compares values with standard * QVariant-based comparison operator. If the property value in a child and a * parent is not the same, then it is not inherited. */ class KRITAFLAKE_EXPORT KoSvgTextProperties { public: /** * Defines a set of supported properties. See SVG 1.1 for details. */ enum PropertyId { WritingModeId, DirectionId, UnicodeBidiId, TextAnchorId, DominantBaselineId, AlignmentBaselineId, BaselineShiftModeId, BaselineShiftValueId, KerningId, GlyphOrientationVerticalId, GlyphOrientationHorizontalId, LetterSpacingId, WordSpacingId, FontFamiliesId, FontStyleId, FontIsSmallCapsId, FontStretchId, FontWeightId, FontSizeId, FontSizeAdjustId, TextDecorationId, FillId, StrokeId }; public: KoSvgTextProperties(); ~KoSvgTextProperties(); KoSvgTextProperties(const KoSvgTextProperties &rhs); KoSvgTextProperties& operator=(const KoSvgTextProperties &rhs); /** * Set the property \p id to \p value */ void setProperty(PropertyId id, const QVariant &value); /** * Check if property \p id is present in this properties set */ bool hasProperty(PropertyId id) const; /** * Return the value of property \p id. If the property doesn't exist in * the shape, return \p defaultValue instead. */ QVariant property(PropertyId id, const QVariant &defaultValue = QVariant()) const; /** * Remove property \p id from the set */ void removeProperty(PropertyId id); /** * Return the value of property \p id. If the property doesn't exist in the * shape, return the default value define in SVG 1.1. */ QVariant propertyOrDefault(PropertyId id) const; /** * Return a list of properties contained in this set */ QList properties() const; /** * Return true if the set contains no properties */ bool isEmpty() const; /** * Reset all non-inheritable properties to default values. The set of * non-inheritable properties is define by SVG 1.1. Used by the loading - * code for resetting state automata's properties on entering a . + * code for resetting state automata's properties on entering a \. */ void resetNonInheritableToDefault(); /** * Apply properties from the parent shape. The property is set **iff** the * property is inheritable according to SVG and this set does not define * it. */ void inheritFrom(const KoSvgTextProperties &parentProperties); /** * Return true if the property \p id is inherited from \p parentProperties. * The property is considered "inherited" **iff* it is inheritable * according to SVG and the parent defined the same property with the same * value. */ bool inheritsProperty(PropertyId id, const KoSvgTextProperties &parentProperties) const; /** * Return a set of properties that ar **not** inherited from \p * parentProperties. The property is considered "inherited" **iff* it is * inheritable according to SVG and the parent defined the same property * with the same value. */ KoSvgTextProperties ownProperties(const KoSvgTextProperties &parentProperties) const; /** * @brief parseSvgTextAttribute add a property according to an XML attribute value. * @param context shared loading context * @param command XML attribute name * @param value attribute value * * @see supportedXmlAttributes for a list of supported attributes */ void parseSvgTextAttribute(const SvgLoadingContext &context, const QString &command, const QString &value); /** * Convert all the properties of the set into a map of XML attribute/value * pairs. */ QMap convertToSvgTextAttributes() const; /** * Return a list of supported XML attribute names (defined in SVG) */ static QStringList supportedXmlAttributes(); /** * Return a static object that defines default values for all the supported * properties according to SVG */ static const KoSvgTextProperties& defaultProperties(); private: struct Private; const QScopedPointer m_d; }; #endif // KOSVGTEXTPROPERTIES_H diff --git a/libs/flake/text/KoSvgTextShape.h b/libs/flake/text/KoSvgTextShape.h index 6e63952012..8a24d8596a 100644 --- a/libs/flake/text/KoSvgTextShape.h +++ b/libs/flake/text/KoSvgTextShape.h @@ -1,94 +1,94 @@ /* * Copyright (c) 2017 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KOSVGTEXTSHAPE_H #define KOSVGTEXTSHAPE_H #include "kritaflake_export.h" #include #include #include class KoSvgTextProperties; class KoSvgTextShapePrivate; #define KoSvgTextShape_SHAPEID "KoSvgTextShapeID" /** - * KoSvgTextShape is a root chunk of the element subtree. + * KoSvgTextShape is a root chunk of the \ element subtree. */ class KRITAFLAKE_EXPORT KoSvgTextShape : public KoSvgTextChunkShape { public: KoSvgTextShape(); KoSvgTextShape(const KoSvgTextShape &rhs); ~KoSvgTextShape() override; KoShape* cloneShape() const override; void paintComponent(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintContext) override; void paintStroke(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintContext) override; /** * Reset the text shape into initial shape, removing all the child shapes * and precalculated layouts. This method is used by text-updating code to * upload the updated text into shape. The upload code first calls * resetTextShape() and then adds new children. */ void resetTextShape() override; /** * Create a new text layout for the current content of the text shape * chunks tree. The user should always call relayout() after every change * in the text shapes hierarchy. */ void relayout(); QPainterPath textOutline(); protected: /** * Show if the shape is a root of the text hierarchy. Always true for * KoSvgTextShape and always false for KoSvgTextChunkShape */ bool isRootTextNode() const override; void shapeChanged(ChangeType type, KoShape *shape) override; private: Q_DECLARE_PRIVATE(KoSvgTextShape) }; class KoSvgTextShapeFactory : public KoShapeFactoryBase { public: /// constructor KoSvgTextShapeFactory(); ~KoSvgTextShapeFactory() {} KoShape *createDefaultShape(KoDocumentResourceManager *documentResources = 0) const override; KoShape *createShape(const KoProperties *params, KoDocumentResourceManager *documentResources = 0) const override; /// Reimplemented bool supports(const KoXmlElement &e, KoShapeLoadingContext &context) const override; }; #endif // KOSVGTEXTSHAPE_H diff --git a/libs/flake/text/KoSvgTextShapeMarkupConverter.h b/libs/flake/text/KoSvgTextShapeMarkupConverter.h index e7f455c22a..9b58ce2468 100644 --- a/libs/flake/text/KoSvgTextShapeMarkupConverter.h +++ b/libs/flake/text/KoSvgTextShapeMarkupConverter.h @@ -1,144 +1,144 @@ /* * Copyright (c) 2017 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KOSVGTEXTSHAPEMARKUPCONVERTER_H #define KOSVGTEXTSHAPEMARKUPCONVERTER_H #include "kritaflake_export.h" #include #include #include #include class QRectF; class KoSvgTextShape; /** * KoSvgTextShapeMarkupConverter is a utility class for converting a * KoSvgTextShape to/from user-editable markup/svg representation. * * Please note that the converted SVG is **not** the same as when saved into * .kra! Some attributes are dropped to make the editing is easier for the * user. */ class KRITAFLAKE_EXPORT KoSvgTextShapeMarkupConverter { public: KoSvgTextShapeMarkupConverter(KoSvgTextShape *shape); ~KoSvgTextShapeMarkupConverter(); /** * Convert the text shape into two strings: text and styles. Styles string * is non-empty only when the text has some gradient/pattern attached. It is * intended to be places into a separate tab in the GUI. * * @return true on success */ bool convertToSvg(QString *svgText, QString *stylesText); /** * @brief upload the svg representation of text into the shape - * @param svgText part of SVG - * @param stylesText part of SVG (used only for gradients and patterns) + * @param svgText \ part of SVG + * @param stylesText \ part of SVG (used only for gradients and patterns) * @param boundsInPixels bounds of the entire image in pixel. Used for parsing percentage units. * @param pixelsPerInch resolution of the image where we load the shape to * * @return true if the text was parsed successfully. Check `errors()` and `warnings()` for details. */ bool convertFromSvg(const QString &svgText, const QString &stylesText, const QRectF &boundsInPixels, qreal pixelsPerInch); /** * @brief convertToHtml convert the text in the text shape to html * @param htmlText will be filled with correct html representing the text in the shape - * @return true om success + * @return @c true on success */ bool convertToHtml(QString *htmlText); /** * @brief convertFromHtml converted Qt rich text html (and no other: http://doc.qt.io/qt-5/richtext-html-subset.html) to SVG * @param htmlText the input html * @param svgText the converted svg text element * @param styles - * @return true if the conversion was successful + * @return @c true if the conversion was successful */ bool convertFromHtml(const QString &htmlText, QString *svgText, QString *styles); /** * @brief convertDocumentToSvg * @param doc the QTextDocument to convert. * @param svgText the converted svg text element - * @return true if the conversion was successful + * @return @c true if the conversion was successful */ bool convertDocumentToSvg(const QTextDocument *doc, QString *svgText); /** * @brief convertSvgToDocument - * @param svgText the element and it's children as a string. + * @param svgText the \ element and it's children as a string. * @param doc the QTextDocument that the conversion is written to. - * @return true if the conversion was successful + * @return @c true if the conversion was successful */ bool convertSvgToDocument(const QString &svgText, QTextDocument *doc); /** * A list of errors happened during loading the user's text */ QStringList errors() const; /** * A list of warnings produced during loading the user's text */ QStringList warnings() const; /** * @brief style * creates a style string based on the blockformat and the format. * @param format the textCharFormat of the current text. * @param blockFormat the block format of the current text. * @param mostCommon the most common format to compare the format to. * @return a string that can be written into a style element. */ QString style(QTextCharFormat format, QTextBlockFormat blockFormat, QTextCharFormat mostCommon = QTextCharFormat()); /** * @brief stylesFromString * returns a qvector with two textformats: * at 0 is the QTextCharFormat * at 1 is the QTextBlockFormat * @param styles a style string split at ";" * @param currentCharFormat the current charformat to compare against. * @param currentBlockFormat the current blockformat to compare against. * @return A QVector with at 0 a QTextCharFormat and at 1 a QBlockCharFormat. */ static QVector stylesFromString(QStringList styles, QTextCharFormat currentCharFormat, QTextBlockFormat currentBlockFormat); /** * @brief formatDifference * A class to get the difference between two text-char formats. * @param test the format to test * @param reference the format to test against. * @return the difference between the two. */ QTextFormat formatDifference(QTextFormat test, QTextFormat reference); private: struct Private; const QScopedPointer d; }; #endif // KOSVGTEXTSHAPEMARKUPCONVERTER_H diff --git a/libs/image/brushengine/kis_paintop_factory.h b/libs/image/brushengine/kis_paintop_factory.h index 27a9c91628..c6129638a8 100644 --- a/libs/image/brushengine/kis_paintop_factory.h +++ b/libs/image/brushengine/kis_paintop_factory.h @@ -1,116 +1,118 @@ /* * Copyright (c) 2008 Boudewijn Rempt * Copyright (c) 2010 Lukáš Tvrdý * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_PAINTOP_FACTORY_H_ #define KIS_PAINTOP_FACTORY_H_ #include "kis_types.h" #include "kritaimage_export.h" #include #include #include #include #include class KisPainter; class KisPaintOp; class QWidget; class KisPaintOpConfigWidget; /** * The paintop factory is responsible for creating paintops of the specified class. * If there is an optionWidget, the derived paintop itself must support settings, * and it's up to the factory to do that. */ class KRITAIMAGE_EXPORT KisPaintOpFactory : public QObject { Q_OBJECT public: enum PaintopVisibility { AUTO, ALWAYS, NEVER }; /** * @param whiteListedCompositeOps list of compositeops that don't work with this paintop */ KisPaintOpFactory(const QStringList & whiteListedCompositeOps = QStringList()); ~KisPaintOpFactory() override {} static QString categoryStable(); #ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND virtual void preinitializePaintOpIfNeeded(const KisPaintOpSettingsSP settings); #endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */ /** * Create a KisPaintOp with the given settings and painter. * @param settings the settings associated with the input device * @param painter the painter used to draw + * @param node the node used to draw + * @param image the image used to draw */ virtual KisPaintOp * createOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image) = 0; virtual QString id() const = 0; virtual QString name() const = 0; virtual QString category() const = 0; /** * List of usually hidden compositeops that are useful for this paintop. */ QStringList whiteListedCompositeOps() const; /** * @brief icon * @return the icon to represent this paintop. */ virtual QIcon icon(); /** * Create and return an settings object for this paintop. */ virtual KisPaintOpSettingsSP createSettings() = 0; /** * create a widget that can display paintop settings */ virtual KisPaintOpConfigWidget* createConfigWidget(QWidget* parent) = 0; /** * Set the priority of this paintop, as it is shown in the UI; lower number means * it will be show more to the front of the list. * @param newPriority the priority */ void setPriority(int newPriority); int priority() const; /** * This method will be called by the registry after all paintops are loaded * Overwrite to let the factory do something. */ virtual void processAfterLoading() {} private: QStringList m_whiteListedCompositeOps; int m_priority; PaintopVisibility m_visibility; }; #endif diff --git a/libs/image/commands/kis_image_command.h b/libs/image/commands/kis_image_command.h index 0c8b0c04f1..e5f3779449 100644 --- a/libs/image/commands/kis_image_command.h +++ b/libs/image/commands/kis_image_command.h @@ -1,71 +1,72 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2007 Sven Langkamp * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_IMAGE_COMMAND_H_ #define KIS_IMAGE_COMMAND_H_ #include #include #include #include #include "kis_types.h" #include "kis_paint_device.h" /// the base command for commands altering a KisImage class KRITAIMAGE_EXPORT KisImageCommand : public KUndo2Command { public: /** * Constructor * @param name The name that will be shown in the ui * @param image The image the command will be working on. + * @param parent The parent command. */ KisImageCommand(const KUndo2MagicString& name, KisImageWSP image, KUndo2Command *parent = 0); ~KisImageCommand() override; protected: /** * Used for performing the smallest update * after a node has been removed from stack. * First tries to setDirty() node's siblings. * If it doesn't help, performs full refresh. */ class UpdateTarget { public: UpdateTarget(KisImageWSP image, KisNodeSP removedNode, const QRect &updateRect); void update(); private: KisImageWSP m_image; QRect m_updateRect; int m_removedNodeIndex; KisNodeSP m_removedNodeParent; }; protected: KisImageWSP m_image; }; #endif // KIS_IMAGE_COMMAND_H_ diff --git a/libs/image/commands/kis_image_layer_add_command.h b/libs/image/commands/kis_image_layer_add_command.h index aff0848dac..6444c33e8c 100644 --- a/libs/image/commands/kis_image_layer_add_command.h +++ b/libs/image/commands/kis_image_layer_add_command.h @@ -1,53 +1,57 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2007 Sven Langkamp * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_IMAGE_LAYER_ADD_COMMAND_H_ #define KIS_IMAGE_LAYER_ADD_COMMAND_H_ #include #include "kis_types.h" #include "kis_image_command.h" /// The command for adding a layer class KRITAIMAGE_EXPORT KisImageLayerAddCommand : public KisImageCommand { public: /** * Constructor * @param image The image the command will be working on. - * @param layer the layer to add + * @param layer The layer to add + * @param parent The parent node + * @param aboveThis The node above this + * @param doRedoUpdates Whether to make the redo updates + * @param doUndoUpdates Whether to make the undo updates */ KisImageLayerAddCommand(KisImageWSP image, KisNodeSP layer, KisNodeSP parent, KisNodeSP aboveThis, bool doRedoUpdates = true, bool doUndoUpdates = true); KisImageLayerAddCommand(KisImageWSP image, KisNodeSP layer, KisNodeSP parent, quint32 index, bool doRedoUpdates = true, bool doUndoUpdates = true); void redo() override; void undo() override; private: KisNodeSP m_layer; KisNodeSP m_parent; KisNodeSP m_aboveThis; quint32 m_index; bool m_doRedoUpdates; bool m_doUndoUpdates; }; #endif diff --git a/libs/image/commands/kis_image_layer_move_command.h b/libs/image/commands/kis_image_layer_move_command.h index 4b98dd98e7..d89e572bd3 100644 --- a/libs/image/commands/kis_image_layer_move_command.h +++ b/libs/image/commands/kis_image_layer_move_command.h @@ -1,62 +1,63 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2007 Sven Langkamp * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_IMAGE_LAYER_MOVE_COMMAND_H_ #define KIS_IMAGE_LAYER_MOVE_COMMAND_H_ #include #include #include #include "kis_types.h" #include "kis_image_command.h" /// The command for layer moves inside the layer stack class KRITAIMAGE_EXPORT KisImageLayerMoveCommand : public KisImageCommand { public: /** * Command for layer moves inside the layer stack * * @param image the image - * @param layer the moved layer + * @param node the moved node * @param newParent the next parent of the layer * @param newAbove the layer that will be below the layer after the move + * @param doUpdates whether to do updates */ KisImageLayerMoveCommand(KisImageWSP image, KisNodeSP node, KisNodeSP newParent, KisNodeSP newAbove, bool doUpdates = true); KisImageLayerMoveCommand(KisImageWSP image, KisNodeSP node, KisNodeSP newParent, quint32 index); void redo() override; void undo() override; private: KisNodeSP m_layer; KisNodeSP m_prevParent; KisNodeSP m_prevAbove; KisNodeSP m_newParent; KisNodeSP m_newAbove; quint32 m_index; bool m_useIndex; bool m_doUpdates; }; #endif diff --git a/libs/image/filter/kis_color_transformation_filter.h b/libs/image/filter/kis_color_transformation_filter.h index 52b8eacbbb..d495c004cd 100644 --- a/libs/image/filter/kis_color_transformation_filter.h +++ b/libs/image/filter/kis_color_transformation_filter.h @@ -1,48 +1,48 @@ /* * Copyright (c) 2009 Cyrille Berger * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _KIS_COLOR_TRANSFORMATION_FILTER_H_ #define _KIS_COLOR_TRANSFORMATION_FILTER_H_ #include "kis_filter.h" #include "kritaimage_export.h" /** * This is a base class for filters that implement a filter for - * \ref KoColorTransformation based filters. + * KoColorTransformationFactory based filters. */ class KRITAIMAGE_EXPORT KisColorTransformationFilter : public KisFilter { public: KisColorTransformationFilter(const KoID& id, const KoID & category, const QString & entry); ~KisColorTransformationFilter() override; void processImpl(KisPaintDeviceSP device, const QRect& applyRect, const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const override; /** * Create the color transformation that will be applied on the device. */ virtual KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const = 0; KisFilterConfigurationSP factoryConfiguration() const override; }; #endif diff --git a/libs/image/filter/kis_filter.h b/libs/image/filter/kis_filter.h index 10a6964064..3e8ed01dd6 100644 --- a/libs/image/filter/kis_filter.h +++ b/libs/image/filter/kis_filter.h @@ -1,126 +1,126 @@ /* * Copyright (c) 2004,2006-2007 Cyrille Berger * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 _KIS_FILTER_H_ #define _KIS_FILTER_H_ #include #include #include #include "KoID.h" #include "KoColorSpace.h" #include "kis_types.h" #include "kis_base_processor.h" #include "kritaimage_export.h" /** * Basic interface of a Krita filter. */ class KRITAIMAGE_EXPORT KisFilter : public KisBaseProcessor { public: /** * Construct a Krita filter */ KisFilter(const KoID& id, const KoID & category, const QString & entry); ~KisFilter() override; /** * Override this function with the implementation of your filter. * * This is a low level function that expects all the conditions * for the @param device be met. Use usual process() methods * instead. * * @param device the paint device to filter * @param applyRect the rectangle where the filter is applied * @param config the parameters of the filter * @param progressUpdater to pass on the progress the filter is making */ virtual void processImpl(KisPaintDeviceSP device, const QRect& applyRect, const KisFilterConfigurationSP config, KoUpdater* progressUpdater = 0 ) const = 0; /** * Filter \p src device and write the result into \p dst device. * If \p dst is an alpha color space device, it will get special * treatment. * * @param src the source paint device * @param dst the destination paint device * @param selection the selection * @param applyRect the rectangle where the filter is applied * @param config the parameters of the filter * @param progressUpdater to pass on the progress the filter is making */ void process(const KisPaintDeviceSP src, KisPaintDeviceSP dst, KisSelectionSP selection, const QRect& applyRect, const KisFilterConfigurationSP config, KoUpdater* progressUpdater = 0 ) const; /** * A convenience method for a two-device process() function */ void process(KisPaintDeviceSP device, const QRect& applyRect, const KisFilterConfigurationSP config, KoUpdater* progressUpdater = 0 ) const; /** * Some filters need pixels outside the current processing rect to compute the new * value (for instance, convolution filters) */ virtual QRect neededRect(const QRect & rect, const KisFilterConfigurationSP config, int lod) const; /** - * Similar to \ref neededRect: some filters will alter a lot of pixels that are + * Similar to @ref neededRect : some filters will alter a lot of pixels that are * near to each other at the same time. So when you changed a single rectangle * in a device, the actual rectangle that will feel the influence of this change * might be bigger. Use this function to determine that rect. */ virtual QRect changedRect(const QRect & rect, const KisFilterConfigurationSP config, int lod) const; /** * Returns true if the filter is capable of handling LoD scaled planes * when generating preview. */ virtual bool supportsLevelOfDetail(const KisFilterConfigurationSP config, int lod) const; virtual bool needsTransparentPixels(const KisFilterConfigurationSP config, const KoColorSpace *cs) const; protected: QString configEntryGroup() const; void setSupportsLevelOfDetail(bool value); private: bool m_supportsLevelOfDetail; }; #endif diff --git a/libs/image/generator/kis_generator.h b/libs/image/generator/kis_generator.h index 55c393abf5..7beda85a76 100644 --- a/libs/image/generator/kis_generator.h +++ b/libs/image/generator/kis_generator.h @@ -1,91 +1,92 @@ /* * Copyright (c) 2008 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 _KIS_GENERATOR_H_ #define _KIS_GENERATOR_H_ #include #include #include "KoID.h" #include "KoColorSpace.h" #include "kis_types.h" #include "kis_base_processor.h" #include "kritaimage_export.h" class KisProcessingInformation; /** * Basic interface of a Krita generator: a generator is a program * that can fill a paint device with a color. A generator can have a * preferred colorspace. * * Generators can have initial parameter settings that determine the * way a particular generator works, but also state that allows the generator * to continue from one invocation of generate to another (handy for, e.g., * painting) */ class KRITAIMAGE_EXPORT KisGenerator : public KisBaseProcessor { friend class KisGeneratorConfigurationFactory; public: KisGenerator(const KoID& id, const KoID & category, const QString & entry); ~KisGenerator() override; public: /** * Override this function with the implementation of your generator. * * @param dst the destination paint device * @param size the size of the area that is to be filled * @param config the parameters of the filter + * @param progressUpdater the progress updater */ virtual void generate(KisProcessingInformation dst, const QSize& size, const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const = 0; /** * Provided for convenience when no progress reporting is needed. */ virtual void generate(KisProcessingInformation dst, const QSize& size, const KisFilterConfigurationSP config ) const; /** * @param _imageArea the rectangle of the image * @return the rectangle that is affected by this generator, if the generator * is supposed to affect all pixels, then the function should return * @p _imageArea */ virtual QRect generatedRect(QRect _imageArea, const KisFilterConfigurationSP = 0) const; protected: /// @return the name of config group in KConfig QString configEntryGroup() const; }; #endif diff --git a/libs/image/kis_adjustment_layer.h b/libs/image/kis_adjustment_layer.h index 10c2dd64ab..447f0cf422 100644 --- a/libs/image/kis_adjustment_layer.h +++ b/libs/image/kis_adjustment_layer.h @@ -1,123 +1,125 @@ /* * Copyright (c) 2006 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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. */ /** - * @file + * @file kis_adjustment_layer.h * This file is part of the Krita calligra application. It handles * a contains a KisFilter OR a KisLayer, and this class is created * to influence the rendering of layers below this one. Can also * function as a fixating layer. * * @author Boudewijn Rempt * @author comments by hscott * @since 1.5 */ #ifndef KIS_ADJUSTMENT_LAYER_H_ #define KIS_ADJUSTMENT_LAYER_H_ #include #include #include "kis_selection_based_layer.h" class KisFilterConfiguration; /** - * @class KisAdjustmentLayer Contains a KisFilter and a KisSelection. + * @class KisAdjustmentLayer + * @brief Contains a KisFilter and a KisSelection. + * * If the selection is present, it is a mask used by the adjustment layer * to know where to apply the filter, thus the combination is used * to influence the rendering of the layers under this layer * in the layerstack. AdjustmentLayers also function as a kind * of "fixating layers". */ class KRITAIMAGE_EXPORT KisAdjustmentLayer : public KisSelectionBasedLayer { Q_OBJECT public: /** * creates a new adjustment layer with the given * configuration and selection. Note that the selection * will be _copied_ (with COW, though). * @param image the image to set this AdjustmentLayer to * @param name name of the adjustment layer * @param kfc the configuration for the adjustment layer filter * @param selection is a mask used by the adjustment layer to * know where to apply the filter. */ KisAdjustmentLayer(KisImageWSP image, const QString &name, KisFilterConfigurationSP kfc, KisSelectionSP selection); KisAdjustmentLayer(const KisAdjustmentLayer& rhs); ~KisAdjustmentLayer() override; bool accept(KisNodeVisitor &) override; void accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter) override; /** * clones this AdjustmentLayer into a KisNodeSP type. * @return the KisNodeSP returned */ KisNodeSP clone() const override { return KisNodeSP(new KisAdjustmentLayer(*this)); } /** * gets the adjustmentLayer's tool filter * @return QIcon returns the QIcon tool filter */ QIcon icon() const override; /** * gets the AdjustmentLayer properties describing whether * or not the node is locked, visible, and the filter * name is it is a filter. Overrides sectionModelProperties * in KisLayer, and KisLayer overrides * sectionModelProperties in KisBaseNode. * @return KisBaseNode::PropertyList returns a list * of the properties */ KisBaseNode::PropertyList sectionModelProperties() const override; public: /** * \see KisNodeFilterInterface::setFilter() */ void setFilter(KisFilterConfigurationSP filterConfig) override; void setChannelFlags(const QBitArray & channelFlags) override; protected: // override from KisLayer QRect incomingChangeRect(const QRect &rect) const override; // override from KisNode QRect needRect(const QRect &rect, PositionToFilthy pos = N_FILTHY) const override; public Q_SLOTS: /** * gets this AdjustmentLayer. Overrides function in * KisIndirectPaintingSupport * @return this AdjustmentLayer */ KisLayer* layer() { return this; } }; #endif // KIS_ADJUSTMENT_LAYER_H_ diff --git a/libs/image/kis_annotation.h b/libs/image/kis_annotation.h index e106124211..b091236190 100644 --- a/libs/image/kis_annotation.h +++ b/libs/image/kis_annotation.h @@ -1,126 +1,128 @@ /* * This file is part of the KDE project * * Copyright (c) 2005 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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. */ /** - * @file this file is part of the Krita application in calligra + * @file kis_annotation.h + * @brief This file is part of the Krita application in calligra * @author Boudewijn Rempt * @author comments by hscott * @since 1.4 or 2005 */ #ifndef _KIS_ANNOTATION_H_ #define _KIS_ANNOTATION_H_ #include #include #include /** - * @class KisAnnotation A data extension mechanism for Krita. + * @class KisAnnotation + * @brief A data extension mechanism for Krita. * * An annotation can be of something like a QByteArray or a QString or * a more specific datatype that can be attached to an image (or maybe * later, if needed, to a layer) and contains data that must be * associated with an image for purposes of import/export. * * Annotations will be saved to krita images and may be exported in * filetypes that support them. * * Examples of annotations are EXIF data and ICC profiles. */ class KisAnnotation : public KisShared { public: /** * creates a new annotation object. The annotation object cannot * be changed later. * * @param type a non-localized string identifying the type of the * annotation * @param description a localized string describing the annotation * @param data a binary blob containing the annotation data */ KisAnnotation(const QString & type, const QString & description, const QByteArray & data) : m_type(type), m_description(description), m_annotation(data) {} virtual ~KisAnnotation() {} virtual KisAnnotation* clone() const { return new KisAnnotation(*this); } /** * gets a non-localized string identifying the type of the * annotation. * @return a non-localized string identifiying the type of the * annotation */ const QString & type() const { return m_type; } /** * gets a localized string describing the type of annotations for * used interface purposes. * @return a localized string describing the type of the * annotations for user interface purposes. */ const QString & description() const { return m_description; } /** * gets a binary blob representation of this annotation * @return a binary blob representation of this annotation */ const QByteArray & annotation() const { return m_annotation; } /** * @brief displayText: override this to return an interpreted version of the annotation */ virtual QString displayText() const { return QString::fromUtf8(m_annotation); } protected: KisAnnotation(const KisAnnotation &rhs) : KisShared(), m_type(rhs.m_type), m_description(rhs.m_description), m_annotation(rhs.m_annotation) { } protected: QString m_type; QString m_description; QByteArray m_annotation; }; #endif // _KIS_ANNOTATION_H_ diff --git a/libs/image/kis_base_mask_generator.h b/libs/image/kis_base_mask_generator.h index 8df0dfe275..c79aca2d42 100644 --- a/libs/image/kis_base_mask_generator.h +++ b/libs/image/kis_base_mask_generator.h @@ -1,130 +1,134 @@ /* * Copyright (c) 2008-2009 Cyrille Berger * Copyright (c) 2010 Lukáš Tvrdý * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 _KIS_MASK_GENERATOR_H_ #define _KIS_MASK_GENERATOR_H_ #include #include //MSVC requires that Vc come first #include #include #include "kritaimage_export.h" class QDomElement; class QDomDocument; class KisBrushMaskApplicatorBase; const KoID DefaultId("default", ki18n("Default")); ///< generate Krita default mask generator const KoID SoftId("soft", ki18n("Soft")); ///< generate brush mask from former softbrush paintop, where softness is based on curve const KoID GaussId("gauss", ki18n("Gaussian")); ///< generate brush mask with a Gaussian-blurred edge static const int OVERSAMPLING = 4; /** * This is the base class for mask shapes * You should subclass it if you want to create a new * shape. */ class KRITAIMAGE_EXPORT KisMaskGenerator { public: enum Type { CIRCLE, RECTANGLE }; public: /** - * This function creates an auto brush shape with the following value : - * @param w width - * @param h height - * @param fh horizontal fade (fh \< w / 2 ) - * @param fv vertical fade (fv \< h / 2 ) + * This function creates an auto brush shape with the following values: + * @param radius radius + * @param ratio aspect ratio + * @param fh horizontal fade + * @param fv vertical fade + * @param spikes number of spikes + * @param antialiasEdges whether to antialias edges + * @param type type + * @param id the brush identifier */ KisMaskGenerator(qreal radius, qreal ratio, qreal fh, qreal fv, int spikes, bool antialiasEdges, Type type, const KoID& id = DefaultId); KisMaskGenerator(const KisMaskGenerator &rhs); virtual ~KisMaskGenerator(); virtual KisMaskGenerator* clone() const = 0; private: void init(); public: /** * @return the alpha value at the position (x,y) */ virtual quint8 valueAt(qreal x, qreal y) const = 0; virtual bool shouldSupersample() const; virtual bool shouldVectorize() const; virtual KisBrushMaskApplicatorBase* applicator(); virtual void toXML(QDomDocument& , QDomElement&) const; /** * Unserialise a \ref KisMaskGenerator */ static KisMaskGenerator* fromXML(const QDomElement&); qreal width() const; qreal height() const; qreal diameter() const; void setDiameter(qreal value); qreal ratio() const; qreal horizontalFade() const; qreal verticalFade() const; int spikes() const; Type type() const; bool isEmpty() const; void fixRotation(qreal &xr, qreal &yr) const; inline QString id() const { return m_id.id(); } inline QString name() const { return m_id.name(); } static QList maskGeneratorIds(); qreal softness() const; virtual void setSoftness(qreal softness); QString curveString() const; void setCurveString(const QString& curveString); bool antialiasEdges() const; virtual void setScale(qreal scaleX, qreal scaleY); protected: qreal effectiveSrcWidth() const; qreal effectiveSrcHeight() const; private: struct Private; const QScopedPointer d; const KoID& m_id; }; #endif diff --git a/libs/image/kis_datamanager.h b/libs/image/kis_datamanager.h index 3b45d115e8..dcf74d37ba 100644 --- a/libs/image/kis_datamanager.h +++ b/libs/image/kis_datamanager.h @@ -1,349 +1,357 @@ /* * Copyright (c) 2004 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_DATAMANAGER_H_ #define KIS_DATAMANAGER_H_ #include class QRect; class KisPaintDeviceWriter; class QIODevice; #include #include #define ACTUAL_DATAMGR KisTiledDataManager /** * KisDataManager defines the interface that modules responsible for * storing and retrieving data must inmplement. Data modules, like * the tile manager, are responsible for: * * * Storing undo/redo data * * Offering ordered and unordered iterators over rects of pixels * * (eventually) efficiently loading and saving data in a format * that may allow deferred loading. * * A datamanager knows nothing about the type of pixel data except * how many quint8's a single pixel takes. */ class KisDataManager : public ACTUAL_DATAMGR { public: /** * Create a new datamanger where every pixel will take pixelSize bytes and will be initialized * by default with defPixel. The value of defPixel is copied, the caller still owns the pointer. * * Note that if pixelSize > size of the defPixel array, we will happily read beyond the * defPixel array. */ KisDataManager(quint32 pixelSize, const quint8 *defPixel) : ACTUAL_DATAMGR(pixelSize, defPixel) {} KisDataManager(const KisDataManager& dm) : ACTUAL_DATAMGR(dm) { } ~KisDataManager() override { } public: /** * Sets the default pixel. New data will be initialised with this pixel. The pixel is copied: the * caller still owns the pointer. */ inline void setDefaultPixel(const quint8 *defPixel) { return ACTUAL_DATAMGR::setDefaultPixel(defPixel); } /** * Get a pointer to the default pixel. */ inline const quint8 *defaultPixel() const { return ACTUAL_DATAMGR::defaultPixel(); } /** * Reguests a memento from the data manager. There is only one memento active * at any given moment for a given paint device and all and any * write actions on the datamanger builds undo data into this memento * necessary to rollback the transaction. */ inline KisMementoSP getMemento() { return ACTUAL_DATAMGR::getMemento(); } /** * Restores the image data to the state at the time of the getMemento() call. * * Note that rollback should be performed with mementos in the reverse order of * their creation, as mementos only store incremental changes */ inline void rollback(KisMementoSP memento) { ACTUAL_DATAMGR::rollback(memento); } /** * Restores the image data to the state at the time of the rollback call of the memento. * * Note that rollforward must only be called when an rollback have previously been performed, and * no intermittent actions have been performed (though it's ok to rollback other mementos and * roll them forward again) */ inline void rollforward(KisMementoSP memento) { ACTUAL_DATAMGR::rollforward(memento); } /** * @returns true if there is a memento active. This means that * iterators can rely on the oldData() function. */ inline bool hasCurrentMemento() const { return ACTUAL_DATAMGR::hasCurrentMemento(); } public: /** * Reads and writes the tiles * */ inline bool write(KisPaintDeviceWriter &writer) { return ACTUAL_DATAMGR::write(writer); } inline bool read(QIODevice *io) { return ACTUAL_DATAMGR::read(io); } inline void purge(const QRect& area) { ACTUAL_DATAMGR::purge(area); } /** * The tiles may be not allocated directly from the glibc, but * instead can be allocated in bigger blobs. After you freed quite * a lot of data and are sure you won't need it anymore, you can * release these pools to save the memory. */ static inline void releaseInternalPools() { ACTUAL_DATAMGR::releaseInternalPools(); } public: /** * Returns the number of bytes a pixel takes */ inline quint32 pixelSize() const { return ACTUAL_DATAMGR::pixelSize(); } /** * Return the extent of the data in x,y,w,h. */ inline void extent(qint32 &x, qint32 &y, qint32 &w, qint32 &h) const { return ACTUAL_DATAMGR::extent(x, y, w, h); } QRect extent() const { return ACTUAL_DATAMGR::extent(); } QRegion region() const { return ACTUAL_DATAMGR::region(); } public: /** * Crop or extend the data to x, y, w, h. */ inline void setExtent(qint32 x, qint32 y, qint32 w, qint32 h) { return ACTUAL_DATAMGR::setExtent(x, y, w, h); } inline void setExtent(const QRect & rect) { setExtent(rect.x(), rect.y(), rect.width(), rect.height()); } public: /** * Clear the specified rect to the specified value. */ inline void clear(qint32 x, qint32 y, qint32 w, qint32 h, quint8 def) { ACTUAL_DATAMGR::clear(x, y, w, h, def); } /** * Clear the specified rect to the specified pixel value. */ inline void clear(qint32 x, qint32 y, qint32 w, qint32 h, const quint8 * def) { ACTUAL_DATAMGR::clear(x, y, w, h, def); } /** * Clear all back to default values. */ inline void clear() { ACTUAL_DATAMGR::clear(); } public: /** * Clones rect from another datamanager. The cloned area will be * shared between both datamanagers as much as possible using * copy-on-write. Parts of the rect that cannot be shared * (cross tiles) are deep-copied, */ inline void bitBlt(KisTiledDataManagerSP srcDM, const QRect &rect) { ACTUAL_DATAMGR::bitBlt(const_cast(srcDM.data()), rect); } /** * The same as \ref bitBlt() but reads old data */ inline void bitBltOldData(KisTiledDataManagerSP srcDM, const QRect &rect) { ACTUAL_DATAMGR::bitBltOldData(const_cast(srcDM.data()), rect); } /** * Clones rect from another datamanager in a rough and fast way. * All the tiles touched by rect will be shared, between both * devices, that means it will copy a bigger area than was * requested. This method is supposed to be used for bitBlt'ing * into temporary paint devices. */ inline void bitBltRough(KisTiledDataManagerSP srcDM, const QRect &rect) { ACTUAL_DATAMGR::bitBltRough(const_cast(srcDM.data()), rect); } /** * The same as \ref bitBltRough() but reads old data */ inline void bitBltRoughOldData(KisTiledDataManagerSP srcDM, const QRect &rect) { ACTUAL_DATAMGR::bitBltRoughOldData(const_cast(srcDM.data()), rect); } public: /** * Write the specified data to x, y. There is no checking on pixelSize! */ inline void setPixel(qint32 x, qint32 y, const quint8 * data) { ACTUAL_DATAMGR::setPixel(x, y, data); } /** * Copy the bytes in the specified rect to a chunk of memory. * The pixelSize in bytes is w * h * pixelSize */ inline void readBytes(quint8 * data, qint32 x, qint32 y, qint32 w, qint32 h, qint32 dataRowStride = -1) const { ACTUAL_DATAMGR::readBytes(data, x, y, w, h, dataRowStride); } /** * Copy the bytes to the specified rect. w * h * pixelSize bytes * will be read, whether the caller prepared them or not. */ inline void writeBytes(const quint8 * data, qint32 x, qint32 y, qint32 w, qint32 h, qint32 dataRowStride = -1) { ACTUAL_DATAMGR::writeBytes(data, x, y, w, h, dataRowStride); } /** * Copy the bytes in the paint device into a vector of arrays of bytes, * where the number of arrays is the number of channels in the * paint device. If the specified area is larger than the paint * device's extent, the default pixel will be read. * - * @param channelsize a vector with for every channel its size in bytes + * @param channelsizes a vector with for every channel its size in bytes + * @param x x coordinate of the top left corner + * @param y y coordinate of the top left corner + * @param w width + * @param h height */ QVector readPlanarBytes(QVector channelsizes, qint32 x, qint32 y, qint32 w, qint32 h) const { return ACTUAL_DATAMGR::readPlanarBytes(channelsizes, x, y, w, h); } /** * Write the data in the separate arrays to the channels. If there * are less vectors than channels, the remaining channels will not * be copied. If any of the arrays points to 0, the channel in * that location will not be touched. If the specified area is * larger than the paint device, the paint device will be * extended. There are no guards: if the area covers more pixels * than there are bytes in the arrays, krita will happily fill * your paint device with areas of memory you never wanted to be * read. Krita may also crash. * * @param planes a vector with a byte array for every plane - * @param channelsize a vector with for every channel its size in + * @param channelsizes a vector with for every channel its size in * bytes + * @param x x coordinate of the top left corner + * @param y y coordinate of the top left corner + * @param w width + * @param h height * * XXX: what about undo? */ void writePlanarBytes(QVector planes, QVector channelsizes, qint32 x, qint32 y, qint32 w, qint32 h) { ACTUAL_DATAMGR::writePlanarBytes(planes, channelsizes, x, y, w, h); } /** * Get the number of contiguous columns starting at x, valid for all values * of y between minY and maxY. */ inline qint32 numContiguousColumns(qint32 x, qint32 minY, qint32 maxY) const { return ACTUAL_DATAMGR::numContiguousColumns(x, minY, maxY); } /** * Get the number of contiguous rows starting at y, valid for all * values of x between minX and maxX. */ inline qint32 numContiguousRows(qint32 y, qint32 minX, qint32 maxX) const { return ACTUAL_DATAMGR::numContiguousRows(y, minX, maxX); } /** * Get the row stride at pixel (x, y). This is the number of bytes * to add to a pointer to pixel (x, y) to access (x, y + 1). */ inline qint32 rowStride(qint32 x, qint32 y) const { return ACTUAL_DATAMGR::rowStride(x, y); } protected: friend class KisRectIterator; friend class KisHLineIterator; friend class KisVLineIterator; }; #endif // KIS_DATAMANAGER_H_ diff --git a/libs/image/kis_edge_detection_kernel.h b/libs/image/kis_edge_detection_kernel.h index 2d8b5d67f0..f5c4d6b7d2 100644 --- a/libs/image/kis_edge_detection_kernel.h +++ b/libs/image/kis_edge_detection_kernel.h @@ -1,129 +1,131 @@ /* * Copyright (c) 2017 Wolthera van Hövell tot Westerflier * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_EDGE_DETECTION_KERNEL_H #define KIS_EDGE_DETECTION_KERNEL_H #include "kritaimage_export.h" #include "kis_types.h" #include class QRect; class KRITAIMAGE_EXPORT KisEdgeDetectionKernel { public: KisEdgeDetectionKernel(); enum FilterType { Simple, //A weird simple method used in our old sobel filter Prewit, //The simpler prewitt detection, which doesn't smooth. SobelVector //Sobel does smooth. The creation of bigger kernels is based on an approach regarding vectors. }; enum FilterOutput { pythagorean, xGrowth, xFall, yGrowth, yFall, radian }; /** * @brief createHorizontalMatrix * @param radius the radius. 1 makes a 3x3 kernel. * @param type One of the entries in the enum Filtertype * @param reverse which direction the gradient goes. * The horizontal gradient by default detects the rightmost edges. * Reversed it selects the leftmost edges. * @return */ static Eigen::Matrix createHorizontalMatrix(qreal radius, FilterType type, bool reverse = false); /** * @brief createVerticalMatrix * @param radius the radius. 1 makes a 3x3 kernel. * @param type One of the entries in the enum Filtertype * @param reverse which direction the gradient goes. * The vertical gradient by default detects the topmost edges. * Reversed it selects the bottommost edges. * @return */ static Eigen::Matrix createVerticalMatrix(qreal radius, FilterType type, bool reverse = false); static KisConvolutionKernelSP createHorizontalKernel(qreal radius, FilterType type, bool denormalize = true, bool reverse = false); static KisConvolutionKernelSP createVerticalKernel(qreal radius, FilterType type, bool denormalize = true, bool reverse = false); static int kernelSizeFromRadius(qreal radius); static qreal sigmaFromRadius(qreal radius); /** * @brief applyEdgeDetection * This applies the edge detection filter to the device. * @param device the device to apply to. * @param rect the affected rect. * @param xRadius the radius of the horizontal sampling, radius of 0 is effectively disabling it. * @param yRadius the radius of the vertical sampling, refius of 0 is effectively disabling it. * @param type the type can be prewitt, sobel or simple, each of which * have a different sampling for the eventual edge detection. * @param channelFlags the affected channels. * @param progressUpdater the progress updater if it exists. + * @param output the output mode. * @param writeToAlpha whether or not to have the result applied to the transparency than the color channels, * this is useful for fringe effects. */ static void applyEdgeDetection(KisPaintDeviceSP device, const QRect& rect, qreal xRadius, qreal yRadius, FilterType type, const QBitArray &channelFlags, KoUpdater *progressUpdater, FilterOutput output = pythagorean, bool writeToAlpha = false); /** * @brief converToNormalMap * Convert a channel of the device to a normal map. The channel will be interpreted as a heightmap. * @param device the device * @param rect the rectangle to apply this to. * @param xRadius the xradius * @param yRadius the yradius * @param type the edge detection filter. * @param channelToConvert the channel to use as a grayscale. * @param channelOrder the order in which the xyz coordinates ought to be written to the pixels. - * @param channelFlags + * @param channelFlip whether to flip the channels + * @param channelFlags the channel flags * @param progressUpdater */ static void convertToNormalMap(KisPaintDeviceSP device, const QRect & rect, qreal xRadius, qreal yRadius, FilterType type, int channelToConvert, QVector channelOrder, QVector channelFlip, const QBitArray &channelFlags, KoUpdater *progressUpdater); }; #endif // KIS_EDGE_DETECTION_KERNEL_H diff --git a/libs/image/kis_fill_painter.h b/libs/image/kis_fill_painter.h index 404f070b84..8e04c41caa 100644 --- a/libs/image/kis_fill_painter.h +++ b/libs/image/kis_fill_painter.h @@ -1,282 +1,282 @@ /* * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 Bart Coppens * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_FILL_PAINTER_H_ #define KIS_FILL_PAINTER_H_ #include #include #include #include #include "kis_painter.h" #include "kis_types.h" #include "kis_selection.h" #include class KisFilterConfiguration; // XXX: Filling should set dirty rect. /** * This painter can be used to fill paint devices in different ways. This can also be used * for flood filling related operations. */ class KRITAIMAGE_EXPORT KisFillPainter : public KisPainter { public: /** * Construct an empty painter. Use the begin(KisPaintDeviceSP) method to attach * to a paint device */ KisFillPainter(); /** * Start painting on the specified paint device */ KisFillPainter(KisPaintDeviceSP device); KisFillPainter(KisPaintDeviceSP device, KisSelectionSP selection); private: void initFillPainter(); public: /** * Fill a rectangle with black transparent pixels (0, 0, 0, 0 for RGBA). */ void eraseRect(qint32 x1, qint32 y1, qint32 w, qint32 h); /** * Overloaded version of the above function. */ void eraseRect(const QRect& rc); /** * Fill current selection of KisPainter with a specified \p color. * * The filling rect is limited by \p rc to allow multithreaded * filling/processing. */ void fillSelection(const QRect &rc, const KoColor &color); /** * Fill a rectangle with a certain color. */ void fillRect(qint32 x, qint32 y, qint32 w, qint32 h, const KoColor& c); /** * Overloaded version of the above function. */ void fillRect(const QRect& rc, const KoColor& c); /** * Fill a rectangle with a certain color and opacity. */ void fillRect(qint32 x, qint32 y, qint32 w, qint32 h, const KoColor& c, quint8 opacity); /** * Overloaded version of the above function. */ void fillRect(const QRect& rc, const KoColor& c, quint8 opacity); /** * Fill a rectangle with a certain pattern. The pattern is repeated if it does not fit the * entire rectangle. */ void fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KoPatternSP pattern, const QPoint &offset = QPoint()); /** * Fill a rectangle with a certain pattern. The pattern is repeated if it does not fit the * entire rectangle. */ void fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KisPaintDeviceSP device, const QRect& deviceRect); /** * Overloaded version of the above function. */ void fillRect(const QRect& rc, const KoPatternSP pattern, const QPoint &offset = QPoint()); /** * Fill the specified area with the output of the generator plugin that is configured * in the generator parameter */ void fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KisFilterConfigurationSP generator); /** * Fills the enclosed area around the point with the set color. If * there is a selection, the whole selection is filled. Note that * you must have set the width and height on the painter if you * don't have a selection. * * @param startX the X position where the floodfill starts * @param startY the Y position where the floodfill starts * @param sourceDevice the sourceDevice that determines the area that * is floodfilled if sampleMerged is on */ void fillColor(int startX, int startY, KisPaintDeviceSP sourceDevice); /** * Fills the enclosed area around the point with the set pattern. * If there is a selection, the whole selection is filled. Note * that you must have set the width and height on the painter if * you don't have a selection. * * @param startX the X position where the floodfill starts * @param startY the Y position where the floodfill starts * @param sourceDevice the sourceDevice that determines the area that * is floodfilled if sampleMerged is on */ void fillPattern(int startX, int startY, KisPaintDeviceSP sourceDevice); /** * Returns a selection mask for the floodfill starting at the specified position. * * @param startX the X position where the floodfill starts * @param startY the Y position where the floodfill starts * @param sourceDevice the sourceDevice that determines the area that * is floodfilled if sampleMerged is on */ KisSelectionSP createFloodSelection(int startX, int startY, KisPaintDeviceSP sourceDevice); /** * Set the threshold for floodfill. The range is 0-255: 0 means the fill will only * fill parts that are the exact same color, 255 means anything will be filled */ void setFillThreshold(int threshold); /** Returns the fill threshold, see setFillThreshold for details */ int fillThreshold() const { return m_threshold; } bool useCompositioning() const { return m_useCompositioning; } void setUseCompositioning(bool useCompositioning) { m_useCompositioning = useCompositioning; } /** Sets the width of the paint device */ void setWidth(int w) { m_width = w; } /** Sets the height of the paint device */ void setHeight(int h) { m_height = h; } /** If true, floodfill doesn't fill outside the selected area of a layer */ bool careForSelection() const { return m_careForSelection; } /** Set caring for selection. See careForSelection for details */ void setCareForSelection(bool set) { m_careForSelection = set; } /** Sets the auto growth/shrinking radius */ void setSizemod(int sizemod) { m_sizemod = sizemod; } - /** Sets how much to auto-grow or shrink (if @param sizemod is negative) the selection + /** Sets how much to auto-grow or shrink (if @p sizemod is negative) the selection flood before painting, this affects every fill operation except fillRect */ int sizemod() { return m_sizemod; } /** Sets feathering radius */ void setFeather(int feather) { m_feather = feather; } /** defines the feathering radius for selection flood operations, this affects every fill operation except fillRect */ uint feather() { return m_feather; } private: // for floodfill void genericFillStart(int startX, int startY, KisPaintDeviceSP sourceDevice); void genericFillEnd(KisPaintDeviceSP filled); KisSelectionSP m_fillSelection; int m_feather; int m_sizemod; int m_threshold; int m_width, m_height; QRect m_rect; bool m_careForSelection; bool m_useCompositioning; }; inline void KisFillPainter::fillRect(qint32 x, qint32 y, qint32 w, qint32 h, const KoColor& c) { fillRect(x, y, w, h, c, OPACITY_OPAQUE_U8); } inline void KisFillPainter::fillRect(const QRect& rc, const KoColor& c) { fillRect(rc.x(), rc.y(), rc.width(), rc.height(), c, OPACITY_OPAQUE_U8); } inline void KisFillPainter::eraseRect(qint32 x1, qint32 y1, qint32 w, qint32 h) { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KoColor c(Qt::black, cs); fillRect(x1, y1, w, h, c, OPACITY_TRANSPARENT_U8); } inline void KisFillPainter::eraseRect(const QRect& rc) { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KoColor c(Qt::black, cs); fillRect(rc.x(), rc.y(), rc.width(), rc.height(), c, OPACITY_TRANSPARENT_U8); } inline void KisFillPainter::fillRect(const QRect& rc, const KoColor& c, quint8 opacity) { fillRect(rc.x(), rc.y(), rc.width(), rc.height(), c, opacity); } inline void KisFillPainter::setFillThreshold(int threshold) { m_threshold = threshold; } #endif //KIS_FILL_PAINTER_H_ diff --git a/libs/image/kis_filter_weights_applicator.h b/libs/image/kis_filter_weights_applicator.h index 1e8d8c9a18..772d770279 100644 --- a/libs/image/kis_filter_weights_applicator.h +++ b/libs/image/kis_filter_weights_applicator.h @@ -1,332 +1,332 @@ /* * Copyright (c) 2012 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 __KIS_FILTER_WEIGHTS_APPLICATOR_H #define __KIS_FILTER_WEIGHTS_APPLICATOR_H #include "kis_fixed_point_maths.h" #include "kis_filter_weights_buffer.h" #include "kis_iterator_ng.h" #include #include namespace tmp { template iter createIterator(KisPaintDeviceSP dev, qint32 start, qint32 lineNum, qint32 len); template <> KisHLineIteratorSP createIterator (KisPaintDeviceSP dev, qint32 start, qint32 lineNum, qint32 len) { return dev->createHLineIteratorNG(start, lineNum, len); } template <> KisVLineIteratorSP createIterator (KisPaintDeviceSP dev, qint32 start, qint32 lineNum, qint32 len) { return dev->createVLineIteratorNG(lineNum, start, len); } } /** * \class KisFilterWeightsApplicator * * This is a main class for transforming a line of pixel data. It * transforms lines from \p src into \p dst using \p scale, \p shear * and offset (\p dx) parameters. * * Notation: - * _l -- leftmost border of the pixel - * _c -- center of the pixel + * \_l -- leftmost border of the pixel + * \_c -- center of the pixel * * * Example calculation of an offset (see calculateBlendSpan()): * scale = 0.5; - * offset = + * offset = \ * * +------ dst_l * | * | +-- dst_c * | | * * dst: | * | * | * | * * src: | * | * | * | * | * | * | * | * | * * ||| * ||+--- next_c_in_src * ||| * |+---- dst_c_in_src * ||| * |++--- offset (near zero, measured in dst coordinates) * | * +-- _l position of the pixel, which is considered - * cetral in the weights buffer + * central in the weights buffer * * Another example calculation of an offset (see calculateBlendSpan()): * scale = 0.5; - * offset = + * offset = \ * * +------ dst_l * | * | +-- dst_c * | | * * dst: | * | * | * | * * src: | * | * | * | * | * | * | * | * | * * || | * || +--- next_c_in_src * || | * +------ dst_c_in_src * || | * +|-+--- offset (near 0.5, measured in dst coordinates) * | * +-- _l position of the pixel, which is considered - * cetral in the weights buffer + * central in the weights buffer */ class KisFilterWeightsApplicator { public: KisFilterWeightsApplicator(KisPaintDeviceSP src, KisPaintDeviceSP dst, qreal realScale, qreal shear, qreal dx, bool clampToEdge) : m_src(src), m_dst(dst), m_realScale(realScale), m_shear(shear), m_dx(dx), m_clampToEdge(clampToEdge) { } struct BlendSpan { KisFilterWeightsBuffer::FilterWeights *weights; int firstBlendPixel; // in src coords KisFixedPoint offset; KisFixedPoint offsetInc; }; inline BlendSpan calculateBlendSpan(int dst_l, int line, KisFilterWeightsBuffer *buffer) const { KisFixedPoint dst_c = l_to_c(dst_l); KisFixedPoint dst_c_in_src = dstToSrc(dst_c.toFloat(), line); KisFixedPoint next_c_in_src = (dst_c_in_src - qreal(0.5)).toIntCeil() + qreal(0.5); BlendSpan span; span.offset = (next_c_in_src - dst_c_in_src) * buffer->weightsPositionScale(); span.offsetInc = buffer->weightsPositionScale(); Q_ASSERT(span.offset <= span.offsetInc); span.weights = buffer->weights(span.offset); span.firstBlendPixel = next_c_in_src.toIntFloor() - span.weights->centerIndex; return span; } class LinePos { public: LinePos() : m_start(0), m_size(0) { } LinePos(int start, int size) : m_start(start), m_size(size) { } inline int start() const { return m_start; } /** * WARNING: be careful! This is not the same as * QRect::right()! This is an equivalent of (QRect::right() + * QRect::width()) or QRectF::right(), that is it points to * the pixel after(!) the actual last pixel. See Qt docs for * more info about this historical difference. */ inline int end() const { return m_start + m_size; } inline int size() const { return m_size; } inline void unite(const LinePos &rhs) { if (m_size > 0) { int newStart = qMin(start(), rhs.start()); int newEnd = qMax(end(), rhs.end()); m_start = newStart; m_size = newEnd - newStart; } else { m_start = rhs.start(); m_size = rhs.size(); } } private: int m_start; int m_size; }; template LinePos processLine(LinePos srcLine, int line, KisFilterWeightsBuffer *buffer, qreal filterSupport) { int dstStart; int dstEnd; int leftSrcBorder; int rightSrcBorder; if (m_realScale >= 0) { dstStart = findAntialiasedDstStart(srcLine.start(), filterSupport, line); dstEnd = findAntialiasedDstEnd(srcLine.end(), filterSupport, line); leftSrcBorder = getLeftSrcNeedBorder(dstStart, line, buffer); rightSrcBorder = getRightSrcNeedBorder(dstEnd - 1, line, buffer); } else { dstStart = findAntialiasedDstStart(srcLine.end(), filterSupport, line); dstEnd = findAntialiasedDstEnd(srcLine.start(), filterSupport, line); leftSrcBorder = getLeftSrcNeedBorder(dstEnd - 1, line, buffer); rightSrcBorder = getRightSrcNeedBorder(dstStart, line, buffer); } if (dstStart >= dstEnd) return LinePos(dstStart, 0); if (leftSrcBorder >= rightSrcBorder) return LinePos(dstStart, 0); if (leftSrcBorder > srcLine.start()) return LinePos(dstStart, 0); if (srcLine.end() > rightSrcBorder) return LinePos(dstStart, 9); int pixelSize = m_src->pixelSize(); KoMixColorsOp *mixOp = m_src->colorSpace()->mixColorsOp(); const KoColor defaultPixelObject = m_src->defaultPixel(); const quint8 *defaultPixel = defaultPixelObject.data(); const quint8 *borderPixel = defaultPixel; quint8 *srcLineBuf = new quint8[pixelSize * (rightSrcBorder - leftSrcBorder)]; int i = leftSrcBorder; quint8 *bufPtr = srcLineBuf; T srcIt = tmp::createIterator(m_src, srcLine.start(), line, srcLine.size()); if (m_clampToEdge) { borderPixel = srcIt->rawData(); } for (; i < srcLine.start(); i++, bufPtr+=pixelSize) { memcpy(bufPtr, borderPixel, pixelSize); } for (; i < srcLine.end(); i++, bufPtr+=pixelSize) { quint8 *data = srcIt->rawData(); memcpy(bufPtr, data, pixelSize); memcpy(data, defaultPixel, pixelSize); srcIt->nextPixel(); } if (m_clampToEdge) { borderPixel = bufPtr - pixelSize; } for (; i < rightSrcBorder; i++, bufPtr+=pixelSize) { memcpy(bufPtr, borderPixel, pixelSize); } const quint8 **colors = new const quint8* [buffer->maxSpan()]; T dstIt = tmp::createIterator(m_dst, dstStart, line, dstEnd - dstStart); for (int i = dstStart; i < dstEnd; i++) { BlendSpan span = calculateBlendSpan(i, line, buffer); int bufIndexStart = span.firstBlendPixel - leftSrcBorder; int bufIndexEnd = bufIndexStart + span.weights->span; const quint8 **colorsPtr = colors; for (int j = bufIndexStart; j < bufIndexEnd; j++) { *(colorsPtr++) = srcLineBuf + j * pixelSize; } mixOp->mixColors(colors, span.weights->weight, span.weights->span, dstIt->rawData()); dstIt->nextPixel(); } delete[] colors; delete[] srcLineBuf; return LinePos(dstStart, qMax(0, dstEnd - dstStart)); } private: int findAntialiasedDstStart(int src_l, qreal support, int line) { qreal dst = srcToDst(src_l, line); return !m_clampToEdge ? floor(dst - support) : floor(dst); } int findAntialiasedDstEnd(int src_l, qreal support, int line) { qreal dst = srcToDst(src_l, line); return !m_clampToEdge ? ceil(dst + support) : ceil(dst); } int getLeftSrcNeedBorder(int dst_l, int line, KisFilterWeightsBuffer *buffer) { BlendSpan span = calculateBlendSpan(dst_l, line, buffer); return span.firstBlendPixel; } int getRightSrcNeedBorder(int dst_l, int line, KisFilterWeightsBuffer *buffer) { BlendSpan span = calculateBlendSpan(dst_l, line, buffer); return span.firstBlendPixel + span.weights->span; } inline KisFixedPoint l_to_c(KisFixedPoint pixel_l) const { return pixel_l + KisFixedPoint(qreal(0.5)); } inline KisFixedPoint c_to_l(KisFixedPoint pixel_c) const { return pixel_c - KisFixedPoint(qreal(0.5)); } inline qreal srcToDst(qreal src, int line) const { return src * m_realScale + m_dx + line * m_shear; } inline qreal dstToSrc(qreal dst, int line) const { return (dst - m_dx - line * m_shear) / m_realScale; } private: KisPaintDeviceSP m_src; KisPaintDeviceSP m_dst; qreal m_realScale; qreal m_shear; qreal m_dx; bool m_clampToEdge; }; #endif /* __KIS_FILTER_WEIGHTS_APPLICATOR_H */ diff --git a/libs/image/kis_fixed_paint_device.h b/libs/image/kis_fixed_paint_device.h index 3b2d03e92a..78462501f1 100644 --- a/libs/image/kis_fixed_paint_device.h +++ b/libs/image/kis_fixed_paint_device.h @@ -1,202 +1,207 @@ /* * Copyright (c) 2009 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_FIXED_PAINT_DEVICE_H #define KIS_FIXED_PAINT_DEVICE_H #include #include #include "kis_shared.h" #include #include #include #include "KisOptimizedByteArray.h" class KoColor; /** * A fixed paint device is a simple paint device that consists of an array * of bytes and a rectangle. It cannot grow, it cannot shrink, all you can * do is fill the paint device with the right bytes and use it as an argument * to KisPainter or use the bytes as an argument to KoColorSpace functions. */ class KRITAIMAGE_EXPORT KisFixedPaintDevice : public KisShared { public: KisFixedPaintDevice(const KoColorSpace* colorSpace, KisOptimizedByteArray::MemoryAllocatorSP allocator = KisOptimizedByteArray::MemoryAllocatorSP()); virtual ~KisFixedPaintDevice(); /** * Deep copy the fixed paint device, including the data. */ KisFixedPaintDevice(const KisFixedPaintDevice& rhs); /** * Deep copy the fixed paint device, including the data. */ KisFixedPaintDevice& operator=(const KisFixedPaintDevice& rhs); /** * setRect sets the rect of the fixed paint device to rect. * This will _not_ create the associated data area. * - * @rect the bounds in pixels. The x,y of the rect represent the origin + * @param rc the bounds in pixels. The x,y of the rect represent the origin * of the fixed paint device. */ void setRect(const QRect& rc); /** * @return the rect that the data represents */ QRect bounds() const; /** * @return the amount of allocated pixels (you can fake the size with setRect/bounds) * It is useful to know the accumulated memory size in pixels (not in bytes) for optimizations to avoid re-allocation. */ int allocatedPixels() const; /** * @return the pixelSize associated with this fixed paint device. */ quint32 pixelSize() const; const KoColorSpace* colorSpace() const { return m_colorSpace; } /** * initializes the paint device. * * @param defaultValue the default byte with which all pixels will be filled. * @return false if the allocation failed. */ bool initialize(quint8 defaultValue = 0); /** * Changed the size of the internal buffer to accommodate the exact number of bytes * needed to store area bounds(). The allocated data is *not* initialized! */ void reallocateBufferWithoutInitialization(); /** * If the size of the internal buffer is smaller than the one needed to accommodate * bounds(), resize the buffer. Otherwise, do nothing. The allocated data is neither * copying or initialized! */ void lazyGrowBufferWithoutInitialization(); /** * @return a pointer to the beginning of the data associated with this fixed paint device. */ quint8* data(); const quint8* constData() const; quint8* data() const; /** * Read the bytes representing the rectangle described by x, y, w, h into * data. If data is not big enough, Krita will gladly overwrite the rest * of your precious memory. * * Since this is a copy, you need to make sure you have enough memory. * * The reading is done only if the rectangular area x,y,w,h is inside the bounds of the device * and the device is not empty */ void readBytes(quint8 * dstData, qint32 x, qint32 y, qint32 w, qint32 h) const; /** * Converts the paint device to a different colorspace */ void convertTo(const KoColorSpace * dstColorSpace = 0, KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags = KoColorConversionTransformation::internalConversionFlags()); /** * Fill this paint device with the data from image * + * @param image the image * @param srcProfileName name of the RGB profile to interpret the image as. 0 is interpreted as sRGB */ virtual void convertFromQImage(const QImage& image, const QString &srcProfileName); /** * Create an RGBA QImage from a rectangle in the paint device. * + * @param dstProfile RGB profile to use in conversion. May be 0, in which + * case it's up to the color strategy to choose a profile (most + * like sRGB). * @param x Left coordinate of the rectangle * @param y Top coordinate of the rectangle * @param w Width of the rectangle in pixels * @param h Height of the rectangle in pixels - * @param dstProfile RGB profile to use in conversion. May be 0, in which - * case it's up to the color strategy to choose a profile (most - * like sRGB). + * @param renderingIntent Rendering intent + * @param conversionFlags Conversion flags */ virtual QImage convertToQImage(const KoColorProfile *dstProfile, qint32 x, qint32 y, qint32 w, qint32 h, KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags = KoColorConversionTransformation::internalConversionFlags()) const; /** * Create an RGBA QImage from a rectangle in the paint device. The * rectangle is defined by the parent image's bounds. * * @param dstProfile RGB profile to use in conversion. May be 0, in which * case it's up to the color strategy to choose a profile (most * like sRGB). + * @param renderingIntent The rendering intent of conversion. + * @param conversionFlags The conversion flags. */ virtual QImage convertToQImage(const KoColorProfile *dstProfile, KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags = KoColorConversionTransformation::internalConversionFlags()) const; /** * Clear the given rectangle to transparent black. * * XXX: this will not (yet) expand the paint device to contain the specified rect * but if the paintdevice has not been initialized, it will be. */ void clear(const QRect & rc); /** * Fill the given rectangle with the given pixel. This does not take the * selection into account. * * XXX: this will not (yet) expand the paint device to contain the specified rect * but if the paintdevice has not been initialized, it will be. */ void fill(qint32 x, qint32 y, qint32 w, qint32 h, const quint8 *fillPixel); void fill(const QRect &rc, const KoColor &color); /** * Mirrors the device. */ void mirror(bool horizontal, bool vertical); private: const KoColorSpace* m_colorSpace; QRect m_bounds; KisOptimizedByteArray m_data; }; #endif diff --git a/libs/image/kis_image.h b/libs/image/kis_image.h index 20225814b5..0e66d8e718 100644 --- a/libs/image/kis_image.h +++ b/libs/image/kis_image.h @@ -1,1123 +1,1128 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2007 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_IMAGE_H_ #define KIS_IMAGE_H_ #include #include #include #include #include #include #include #include "kis_paint_device.h" // msvc cannot handle forward declarations, so include kis_paint_device here #include "kis_types.h" #include "kis_shared.h" #include "kis_node_graph_listener.h" #include "kis_node_facade.h" #include "kis_image_interfaces.h" #include "kis_strokes_queue_undo_result.h" #include class KisDocument; class KoColorSpace; class KoColor; class KisCompositeProgressProxy; class KisUndoStore; class KisUndoAdapter; class KisImageSignalRouter; class KisPostExecutionUndoAdapter; class KisFilterStrategy; class KoColorProfile; class KisLayerComposition; class KisSpontaneousJob; class KisImageAnimationInterface; class KUndo2MagicString; class KisProofingConfiguration; namespace KisMetaData { class MergeStrategy; } /** * This is the image class, it contains a tree of KisLayer stack and * meta information about the image. And it also provides some * functions to manipulate the whole image. */ class KRITAIMAGE_EXPORT KisImage : public QObject, public KisStrokesFacade, public KisStrokeUndoFacade, public KisUpdatesFacade, public KisProjectionUpdateListener, public KisNodeFacade, public KisNodeGraphListener, public KisShared { Q_OBJECT public: - /// @param colorSpace can be null. in that case it will be initialised to a default color space. + /// @p colorSpace can be null. In that case, it will be initialised to a default color space. KisImage(KisUndoStore *undoStore, qint32 width, qint32 height, const KoColorSpace *colorSpace, const QString& name); ~KisImage() override; public: // KisNodeGraphListener implementation void aboutToAddANode(KisNode *parent, int index) override; void nodeHasBeenAdded(KisNode *parent, int index) override; void aboutToRemoveANode(KisNode *parent, int index) override; void nodeChanged(KisNode * node) override; void invalidateAllFrames() override; void notifySelectionChanged() override; void requestProjectionUpdate(KisNode *node, const QVector &rects, bool resetAnimationCache) override; void invalidateFrames(const KisTimeRange &range, const QRect &rect) override; void requestTimeSwitch(int time) override; KisNode* graphOverlayNode() const override; public: // KisProjectionUpdateListener implementation void notifyProjectionUpdated(const QRect &rc) override; public: /** * Set the number of threads used by the image's working threads */ void setWorkingThreadsLimit(int value); /** * Return the number of threads available to the image's working threads */ int workingThreadsLimit() const; /** * Makes a copy of the image with all the layers. If possible, shallow * copies of the layers are made. * * \p exactCopy shows if the copied image should look *exactly* the same as * the other one (according to it's .kra xml representation). It means that * the layers will have the same UUID keys and, therefore, you are not * expected to use the copied image anywhere except for saving. Don't use * this option if you plan to work with the copied image later. */ KisImage *clone(bool exactCopy = false); /** * Render the projection onto a QImage. */ QImage convertToQImage(qint32 x1, qint32 y1, qint32 width, qint32 height, const KoColorProfile * profile); /** * Render the projection onto a QImage. * (this is an overloaded function) */ QImage convertToQImage(QRect imageRect, const KoColorProfile * profile); /** * Render a thumbnail of the projection onto a QImage. */ QImage convertToQImage(const QSize& scaledImageSize, const KoColorProfile *profile); /** * [low-level] Lock the image without waiting for all the internal job queues are processed * * WARNING: Don't use it unless you really know what you are doing! Use barrierLock() instead! * * Waits for all the **currently running** internal jobs to complete and locks the image * for writing. Please note that this function does **not** wait for all the internal * queues to process, so there might be some non-finished actions pending. It means that * you just postpone these actions until you unlock() the image back. Until then, then image * might easily be frozen in some inconsistent state. * * The only sane usage for this function is to lock the image for **emergency** * processing, when some internal action or scheduler got hung up, and you just want * to fetch some data from the image without races. * * In all other cases, please use barrierLock() instead! */ void lock(); /** * Unlocks the image and starts/resumes all the pending internal jobs. If the image * has been locked for a non-readOnly access, then all the internal caches of the image * (e.g. lod-planes) are reset and regeneration jobs are scheduled. */ void unlock(); /** * @return return true if the image is in a locked state, i.e. all the internal * jobs are blocked from execution by calling wither lock() or barrierLock(). * * When the image is locked, the user can do some modifications to the image * contents safely without a perspective having race conditions with internal * image jobs. */ bool locked() const; /** * Sets the mask (it must be a part of the node hierarchy already) to be paited on * the top of all layers. This method does all the locking and syncing for you. It * is executed asynchronously. */ void setOverlaySelectionMask(KisSelectionMaskSP mask); /** * \see setOverlaySelectionMask */ KisSelectionMaskSP overlaySelectionMask() const; /** * \see setOverlaySelectionMask */ bool hasOverlaySelectionMask() const; /** * @return the global selection object or 0 if there is none. The * global selection is always read-write. */ KisSelectionSP globalSelection() const; /** * Retrieve the next automatic layername (XXX: fix to add option to return Mask X) */ QString nextLayerName(const QString &baseName = "") const; /** * Set the automatic layer name counter one back. */ void rollBackLayerName(); /** * @brief start asynchronous operation on resizing the image * * The method will resize the image to fit the new size without * dropping any pixel data. The GUI will get correct * notification with old and new sizes, so it adjust canvas origin * accordingly and avoid jumping of the canvas on screen * * @param newRect the rectangle of the image which will be visible * after operation is completed * * Please note that the actual operation starts asynchronously in * a background, so you cannot expect the image having new size * right after this call. */ void resizeImage(const QRect& newRect); /** * @brief start asynchronous operation on cropping the image * * The method will **drop** all the image data outside \p newRect * and resize the image to fit the new size. The GUI will get correct * notification with old and new sizes, so it adjust canvas origin * accordingly and avoid jumping of the canvas on screen * * @param newRect the rectangle of the image which will be cut-out * * Please note that the actual operation starts asynchronously in * a background, so you cannot expect the image having new size * right after this call. */ void cropImage(const QRect& newRect); /** * @brief start asynchronous operation on cropping a subtree of nodes starting at \p node * * The method will **drop** all the layer data outside \p newRect. Neither * image nor a layer will be moved anywhere * + * @param node node to crop * @param newRect the rectangle of the layer which will be cut-out * * Please note that the actual operation starts asynchronously in * a background, so you cannot expect the image having new size * right after this call. */ void cropNode(KisNodeSP node, const QRect& newRect); /** * @brief start asynchronous operation on scaling the image * @param size new image size in pixels * @param xres new image x-resolution pixels-per-pt * @param yres new image y-resolution pixels-per-pt * @param filterStrategy filtering strategy * * Please note that the actual operation starts asynchronously in * a background, so you cannot expect the image having new size * right after this call. */ void scaleImage(const QSize &size, qreal xres, qreal yres, KisFilterStrategy *filterStrategy); /** * @brief start asynchronous operation on scaling a subtree of nodes starting at \p node * @param node node to scale - * @param scaleX, @param scaleY scale coefficient to be applied to the node + * @param center the center of the scaling + * @param scaleX x-scale coefficient to be applied to the node + * @param scaleY y-scale coefficient to be applied to the node * @param filterStrategy filtering strategy + * @param selection the selection we based on * * Please note that the actual operation starts asynchronously in * a background, so you cannot expect the image having new size * right after this call. */ void scaleNode(KisNodeSP node, const QPointF ¢er, qreal scaleX, qreal scaleY, KisFilterStrategy *filterStrategy, KisSelectionSP selection); /** * @brief start asynchronous operation on rotating the image * * The image is resized to fit the rotated rectangle * * @param radians rotation angle in radians * * Please note that the actual operation starts asynchronously in * a background, so you cannot expect the operation being completed * right after the call */ void rotateImage(double radians); /** * @brief start asynchronous operation on rotating a subtree of nodes starting at \p node * * The image is not resized! * * @param node the root of the subtree to rotate * @param radians rotation angle in radians + * @param selection the selection we based on * * Please note that the actual operation starts asynchronously in * a background, so you cannot expect the operation being completed * right after the call */ void rotateNode(KisNodeSP node, double radians, KisSelectionSP selection); /** * @brief start asynchronous operation on shearing the image * * The image is resized to fit the sheared polygon * - * @param angleX, @param angleY are given in degrees. + * @p angleX, @p angleY are given in degrees. * * Please note that the actual operation starts asynchronously in * a background, so you cannot expect the operation being completed * right after the call */ void shear(double angleX, double angleY); /** * @brief start asynchronous operation on shearing a subtree of nodes starting at \p node * * The image is not resized! * * @param node the root of the subtree to rotate - * @param angleX, @param angleY are given in degrees. + * @param angleX x-shear given in degrees. + * @param angleY y-shear given in degrees. + * @param selection the selection we based on * * Please note that the actual operation starts asynchronously in * a background, so you cannot expect the operation being completed * right after the call */ void shearNode(KisNodeSP node, double angleX, double angleY, KisSelectionSP selection); /** * Convert the image and all its layers to the dstColorSpace */ void convertImageColorSpace(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags); /** * Set the color space of the projection (and the root layer) * to dstColorSpace. No conversion is done for other layers, * their colorspace can differ. - * NOTE: Note conversion is done, only regeneration, so no rendering + * @note No conversion is done, only regeneration, so no rendering * intent needed */ void convertProjectionColorSpace(const KoColorSpace *dstColorSpace); // Get the profile associated with this image const KoColorProfile * profile() const; /** * Set the profile of the image to the new profile and do the same for * all layers that have the same colorspace and profile of the image. * It doesn't do any pixel conversion. * * This is essential if you have loaded an image that didn't * have an embedded profile to which you want to attach the right profile. * * This does not create an undo action; only call it when creating or * loading an image. * * @returns false if the profile could not be assigned */ bool assignImageProfile(const KoColorProfile *profile); /** * Returns the current undo adapter. You can add new commands to the * undo stack using the adapter. This adapter is used for a backward * compatibility for old commands created before strokes. It blocks * all the porcessing at the scheduler, waits until it's finished * and executes commands exclusively. */ KisUndoAdapter* undoAdapter() const; /** * This adapter is used by the strokes system. The commands are added * to it *after* redo() is done (in the scheduler context). They are * wrapped into a special command and added to the undo stack. redo() * in not called. */ KisPostExecutionUndoAdapter* postExecutionUndoAdapter() const override; /** * Replace current undo store with the new one. The old store * will be deleted. * This method is used by KisDocument for dropping all the commands * during file loading. */ void setUndoStore(KisUndoStore *undoStore); /** * Return current undo store of the image */ KisUndoStore* undoStore(); /** * Tell the image it's modified; this emits the sigImageModified * signal. This happens when the image needs to be saved */ void setModified(); /** * The default colorspace of this image: new layers will have this * colorspace and the projection will have this colorspace. */ const KoColorSpace * colorSpace() const; /** * X resolution in pixels per pt */ double xRes() const; /** * Y resolution in pixels per pt */ double yRes() const; /** * Set the resolution in pixels per pt. */ void setResolution(double xres, double yres); /** * Convert a document coordinate to a pixel coordinate. * * @param documentCoord PostScript Pt coordinate to convert. */ QPointF documentToPixel(const QPointF &documentCoord) const; /** * Convert a document coordinate to an integer pixel coordinate rounded down. * * @param documentCoord PostScript Pt coordinate to convert. */ QPoint documentToImagePixelFloored(const QPointF &documentCoord) const; /** * Convert a document rectangle to a pixel rectangle. * * @param documentRect PostScript Pt rectangle to convert. */ QRectF documentToPixel(const QRectF &documentRect) const; /** * Convert a pixel coordinate to a document coordinate. * * @param pixelCoord pixel coordinate to convert. */ QPointF pixelToDocument(const QPointF &pixelCoord) const; /** * Convert an integer pixel coordinate to a document coordinate. * The document coordinate is at the centre of the pixel. * * @param pixelCoord pixel coordinate to convert. */ QPointF pixelToDocument(const QPoint &pixelCoord) const; /** * Convert a document rectangle to an integer pixel rectangle. * * @param pixelCoord pixel coordinate to convert. */ QRectF pixelToDocument(const QRectF &pixelCoord) const; /** * Return the width of the image */ qint32 width() const; /** * Return the height of the image */ qint32 height() const; /** * Return the size of the image */ QSize size() const { return QSize(width(), height()); } /** * @return the root node of the image node graph */ KisGroupLayerSP rootLayer() const; /** * Return the projection; that is, the complete, composited * representation of this image. */ KisPaintDeviceSP projection() const; /** * Return the number of layers (not other nodes) that are in this * image. */ qint32 nlayers() const; /** * Return the number of layers (not other node types) that are in * this image and that are hidden. */ qint32 nHiddenLayers() const; /** * Merge all visible layers and discard hidden ones. */ void flatten(KisNodeSP activeNode); /** * Merge the specified layer with the layer * below this layer, remove the specified layer. */ void mergeDown(KisLayerSP l, const KisMetaData::MergeStrategy* strategy); /** * flatten the layer: that is, the projection becomes the layer * and all subnodes are removed. If this is not a paint layer, it will morph * into a paint layer. */ void flattenLayer(KisLayerSP layer); /** * Merges layers in \p mergedLayers and creates a new layer above * \p putAfter */ void mergeMultipleLayers(QList mergedLayers, KisNodeSP putAfter); /// @return the exact bounds of the image in pixel coordinates. QRect bounds() const; /** * Returns the actual bounds of the image, taking LevelOfDetail * into account. This value is used as a bounds() value of * KisDefaultBounds object. */ QRect effectiveLodBounds() const; /// use if the layers have changed _completely_ (eg. when flattening) void notifyLayersChanged(); /** * Sets the default color of the root layer projection. All the layers * will be merged on top of this very color */ void setDefaultProjectionColor(const KoColor &color); /** * \see setDefaultProjectionColor() */ KoColor defaultProjectionColor() const; void setRootLayer(KisGroupLayerSP rootLayer); /** * Add an annotation for this image. This can be anything: Gamma, EXIF, etc. * Note that the "icc" annotation is reserved for the color strategies. * If the annotation already exists, overwrite it with this one. */ void addAnnotation(KisAnnotationSP annotation); /** get the annotation with the given type, can return 0 */ KisAnnotationSP annotation(const QString& type); /** delete the annotation, if the image contains it */ void removeAnnotation(const QString& type); /** * Start of an iteration over the annotations of this image (including the ICC Profile) */ vKisAnnotationSP_it beginAnnotations(); /** end of an iteration over the annotations of this image */ vKisAnnotationSP_it endAnnotations(); /** * Called before the image is deleted and sends the sigAboutToBeDeleted signal */ void notifyAboutToBeDeleted(); KisImageSignalRouter* signalRouter(); /** * Returns whether we can reselect current global selection * * \see reselectGlobalSelection() */ bool canReselectGlobalSelection(); /** * Returns the layer compositions for the image */ QList compositions(); /** * Adds a new layer composition, will be saved with the image */ void addComposition(KisLayerCompositionSP composition); /** * Remove the layer compostion */ void removeComposition(KisLayerCompositionSP composition); /** * Permit or deny the wrap-around mode for all the paint devices * of the image. Note that permitting the wraparound mode will not * necessarily activate it right now. To be activated the wrap * around mode should be 1) permitted; 2) supported by the * currently running stroke. */ void setWrapAroundModePermitted(bool value); /** * \return whether the wrap-around mode is permitted for this * image. If the wrap around mode is permitted and the * currently running stroke supports it, the mode will be * activated for all paint devices of the image. * * \see setWrapAroundMode */ bool wrapAroundModePermitted() const; /** * \return whether the wraparound mode is activated for all the * devices of the image. The mode is activated when both * factors are true: the user permitted it and the stroke * supports it */ bool wrapAroundModeActive() const; /** * \return current level of detail which is used when processing the image. * Current working zoom = 2 ^ (- currentLevelOfDetail()). Default value is * null, which means we work on the original image. */ int currentLevelOfDetail() const; /** * Notify KisImage which level of detail should be used in the * lod-mode. Setting the mode does not guarantee the LOD to be * used. It will be activated only when the stokes supports it. */ void setDesiredLevelOfDetail(int lod); /** * Relative position of the mirror axis center * 0,0 - topleft corner of the image * 1,1 - bottomright corner of the image */ QPointF mirrorAxesCenter() const; /** * Sets the relative position of the axes center * \see mirrorAxesCenter() for details */ void setMirrorAxesCenter(const QPointF &value) const; public Q_SLOTS: /** * Explicitly start regeneration of LoD planes of all the devices * in the image. This call should be performed when the user is idle, * just to make the quality of image updates better. */ void explicitRegenerateLevelOfDetail(); public: /** * Blocks usage of level of detail functionality. After this method * has been called, no new strokes will use LoD. */ void setLevelOfDetailBlocked(bool value); /** * \see setLevelOfDetailBlocked() */ bool levelOfDetailBlocked() const; /** * Notifies that the node collapsed state has changed */ void notifyNodeCollpasedChanged(); KisImageAnimationInterface *animationInterface() const; /** * @brief setProofingConfiguration, this sets the image's proofing configuration, and signals * the proofingConfiguration has changed. * @param proofingConfig - the kis proofing config that will be used instead. */ void setProofingConfiguration(KisProofingConfigurationSP proofingConfig); /** * @brief proofingConfiguration * @return the proofing configuration of the image. */ KisProofingConfigurationSP proofingConfiguration() const; public Q_SLOTS: bool startIsolatedMode(KisNodeSP node); void stopIsolatedMode(); public: KisNodeSP isolatedModeRoot() const; Q_SIGNALS: /** * Emitted whenever an action has caused the image to be - * recomposited. - * - * @param rc The rect that has been recomposited. + * recomposited. Parameter is the rect that has been recomposited. */ void sigImageUpdated(const QRect &); /** Emitted whenever the image has been modified, so that it doesn't match with the version saved on disk. */ void sigImageModified(); /** * The signal is emitted when the size of the image is changed. * \p oldStillPoint and \p newStillPoint give the receiver the * hint about how the new and old rect of the image correspond to * each other. They specify the point of the image around which * the conversion was done. This point will stay still on the * user's screen. That is the \p newStillPoint of the new image * will be painted at the same screen position, where \p * oldStillPoint of the old image was painted. * * \param oldStillPoint is a still point represented in *old* * image coordinates * * \param newStillPoint is a still point represented in *new* * image coordinates */ void sigSizeChanged(const QPointF &oldStillPoint, const QPointF &newStillPoint); void sigProfileChanged(const KoColorProfile * profile); void sigColorSpaceChanged(const KoColorSpace* cs); void sigResolutionChanged(double xRes, double yRes); void sigRequestNodeReselection(KisNodeSP activeNode, const KisNodeList &selectedNodes); /** * Inform the model that a node was changed */ void sigNodeChanged(KisNodeSP node); /** * Inform that the image is going to be deleted */ void sigAboutToBeDeleted(); /** * The signal is emitted right after a node has been connected * to the graph of the nodes. * * WARNING: you must not request any graph-related information * about the node being run in a not-scheduler thread. If you need * information about the parent/siblings of the node connect * with Qt::DirectConnection, get needed information and then * emit another Qt::AutoConnection signal to pass this information * to your thread. See details of the implementation * in KisDummiesfacadeBase. */ void sigNodeAddedAsync(KisNodeSP node); /** * This signal is emitted right before a node is going to removed * from the graph of the nodes. * * WARNING: you must not request any graph-related information * about the node being run in a not-scheduler thread. * * \see comment in sigNodeAddedAsync() */ void sigRemoveNodeAsync(KisNodeSP node); /** * Emitted when the root node of the image has changed. * It happens, e.g. when we flatten the image. When * this happens the receiver should reload information * about the image */ void sigLayersChangedAsync(); /** * Emitted when the UI has requested the undo of the last stroke's * operation. The point is, we cannot deal with the internals of * the stroke without its creator knowing about it (which most * probably cause a crash), so we just forward this request from * the UI to the creator of the stroke. * * If your tool supports undoing part of its work, just listen to * this signal and undo when it comes */ void sigUndoDuringStrokeRequested(); /** * Emitted when the UI has requested the cancellation of * the stroke. The point is, we cannot cancel the stroke * without its creator knowing about it (which most probably * cause a crash), so we just forward this request from the UI * to the creator of the stroke. * * If your tool supports cancelling of its work in the middle * of operation, just listen to this signal and cancel * the stroke when it comes */ void sigStrokeCancellationRequested(); /** * Emitted when the image decides that the stroke should better * be ended. The point is, we cannot just end the stroke * without its creator knowing about it (which most probably * cause a crash), so we just forward this request from the UI * to the creator of the stroke. * * If your tool supports long strokes that may involve multiple * mouse actions in one stroke, just listen to this signal and * end the stroke when it comes. */ void sigStrokeEndRequested(); /** * Same as sigStrokeEndRequested() but is not emitted when the active node * is changed. */ void sigStrokeEndRequestedActiveNodeFiltered(); /** * Emitted when the isolated mode status has changed. * * Can be used by the receivers to catch a fact of forcefully * stopping the isolated mode by the image when some complex * action was requested */ void sigIsolatedModeChanged(); /** * Emitted when one or more nodes changed the collapsed state * */ void sigNodeCollapsedChanged(); /** * Emitted when the proofing configuration of the image is being changed. * */ void sigProofingConfigChanged(); /** * Internal signal for asynchronously requesting isolated mode to stop. Don't use it * outside KisImage, use sigIsolatedModeChanged() instead. */ void sigInternalStopIsolatedModeRequested(); public Q_SLOTS: KisCompositeProgressProxy* compositeProgressProxy(); bool isIdle(bool allowLocked = false); /** * @brief Wait until all the queued background jobs are completed and lock the image. * * KisImage object has a local scheduler that executes long-running image * rendering/modifying jobs (we call them "strokes") in a background. Basically, * one should either access the image from the scope of such jobs (strokes) or * just lock the image before using. * * Calling barrierLock() will wait until all the queued operations are finished * and lock the image, so you can start accessing it in a safe way. * * @p readOnly tells the image if the caller is going to modify the image during * holding the lock. Locking with non-readOnly access will reset all * the internal caches of the image (lod-planes) when the lock status * will be lifted. */ void barrierLock(bool readOnly = false); /** * @brief Tries to lock the image without waiting for the jobs to finish * * Same as barrierLock(), but doesn't block execution of the calling thread * until all the background jobs are finished. Instead, in case of presence of * unfinished jobs in the queue, it just returns false * * @return whether the lock has been acquired * @see barrierLock */ bool tryBarrierLock(bool readOnly = false); /** * Wait for all the internal image jobs to complete and return without locking * the image. This function is handly for tests or other synchronous actions, * when one needs to wait for the result of his actions. */ void waitForDone(); KisStrokeId startStroke(KisStrokeStrategy *strokeStrategy) override; void addJob(KisStrokeId id, KisStrokeJobData *data) override; void endStroke(KisStrokeId id) override; bool cancelStroke(KisStrokeId id) override; /** * @brief blockUpdates block updating the image projection */ void blockUpdates() override; /** * @brief unblockUpdates unblock updating the image project. This * only restarts the scheduler and does not schedule a full refresh. */ void unblockUpdates() override; /** * Disables notification of the UI about the changes in the image. * This feature is used by KisProcessingApplicator. It is needed * when we change the size of the image. In this case, the whole * image will be reloaded into UI by sigSizeChanged(), so there is * no need to inform the UI about individual dirty rects. * * The last call to enableUIUpdates() will return the list of udpates * that were requested while they were blocked. */ void disableUIUpdates() override; /** * \see disableUIUpdates */ QVector enableUIUpdates() override; /** * Disables the processing of all the setDirty() requests that * come to the image. The incoming requests are effectively * *dropped*. * * This feature is used by KisProcessingApplicator. For many cases * it provides its own updates interface, which recalculates the * whole subtree of nodes. But while we change any particular * node, it can ask for an update itself. This method is a way of * blocking such intermediate (and excessive) requests. * * NOTE: this is a convenience function for setProjectionUpdatesFilter() * that installs a predefined filter that eats everything. Please * note that these calls are *not* recursive */ void disableDirtyRequests() override; /** * \see disableDirtyRequests() */ void enableDirtyRequests() override; /** * Installs a filter object that will filter all the incoming projection update * requests. If the filter return true, the incoming update is dropped. * * NOTE: you cannot set filters recursively! */ void setProjectionUpdatesFilter(KisProjectionUpdatesFilterSP filter) override; /** * \see setProjectionUpdatesFilter() */ KisProjectionUpdatesFilterSP projectionUpdatesFilter() const override; void refreshGraphAsync(KisNodeSP root = KisNodeSP()) override; void refreshGraphAsync(KisNodeSP root, const QRect &rc) override; void refreshGraphAsync(KisNodeSP root, const QRect &rc, const QRect &cropRect) override; /** * Triggers synchronous recomposition of the projection */ void refreshGraph(KisNodeSP root = KisNodeSP()); void refreshGraph(KisNodeSP root, const QRect& rc, const QRect &cropRect); void initialRefreshGraph(); /** * Initiate a stack regeneration skipping the recalculation of the * filthy node's projection. * * Works exactly as pseudoFilthy->setDirty() with the only * exception that pseudoFilthy::updateProjection() will not be * called. That is used by KisRecalculateTransformMaskJob to avoid * cyclic dependencies. */ void requestProjectionUpdateNoFilthy(KisNodeSP pseudoFilthy, const QRect &rc, const QRect &cropRect); /** * Adds a spontaneous job to the updates queue. * * A spontaneous job may do some trivial tasks in the background, * like updating the outline of selection or purging unused tiles * from the existing paint devices. */ void addSpontaneousJob(KisSpontaneousJob *spontaneousJob); /** * This method is called by the UI (*not* by the creator of the * stroke) when it thinks the current stroke should undo its last * action, for example, when the user presses Ctrl+Z while some * stroke is active. * * If the creator of the stroke supports undoing of intermediate * actions, it will be notified about this request and can undo * its last action. */ void requestUndoDuringStroke(); /** * This method is called by the UI (*not* by the creator of the * stroke) when it thinks current stroke should be cancelled. If * there is a running stroke that has already been detached from * its creator (ended or cancelled), it will be forcefully * cancelled and reverted. If there is an open stroke present, and * if its creator supports cancelling, it will be notified about * the request and the stroke will be cancelled */ void requestStrokeCancellation(); /** * This method requests the last stroke executed on the image to become undone. * If the stroke is not ended, or if all the Lod0 strokes are completed, the method * returns UNDO_FAIL. If the last Lod0 is going to be finished soon, then UNDO_WAIT * is returned and the caller should just wait for its completion and call global undo * instead. UNDO_OK means one unfinished stroke has been undone. */ UndoResult tryUndoUnfinishedLod0Stroke(); /** * This method is called when image or some other part of Krita * (*not* the creator of the stroke) decides that the stroke * should be ended. If the creator of the stroke supports it, it * will be notified and the stroke will be cancelled */ void requestStrokeEnd(); /** * Same as requestStrokeEnd() but is called by view manager when * the current node is changed. Use to distinguish * sigStrokeEndRequested() and * sigStrokeEndRequestedActiveNodeFiltered() which are used by * KisNodeJugglerCompressed */ void requestStrokeEndActiveNode(); private: KisImage(const KisImage& rhs, KisUndoStore *undoStore, bool exactCopy); KisImage& operator=(const KisImage& rhs); void emitSizeChanged(); void resizeImageImpl(const QRect& newRect, bool cropLayers); void rotateImpl(const KUndo2MagicString &actionName, KisNodeSP rootNode, double radians, bool resizeImage, KisSelectionSP selection); void shearImpl(const KUndo2MagicString &actionName, KisNodeSP rootNode, bool resizeImage, double angleX, double angleY, KisSelectionSP selection); void safeRemoveTwoNodes(KisNodeSP node1, KisNodeSP node2); void refreshHiddenArea(KisNodeSP rootNode, const QRect &preparedArea); void requestProjectionUpdateImpl(KisNode *node, const QVector &rects, const QRect &cropRect); friend class KisImageResizeCommand; void setSize(const QSize& size); friend class KisImageSetProjectionColorSpaceCommand; void setProjectionColorSpace(const KoColorSpace * colorSpace); friend class KisDeselectGlobalSelectionCommand; friend class KisReselectGlobalSelectionCommand; friend class KisSetGlobalSelectionCommand; friend class KisImageTest; friend class Document; // For libkis /** * Replaces the current global selection with globalSelection. If * \p globalSelection is empty, removes the selection object, so that * \ref globalSelection() will return 0 after that. */ void setGlobalSelection(KisSelectionSP globalSelection); /** * Deselects current global selection. * \ref globalSelection() will return 0 after that. */ void deselectGlobalSelection(); /** * Reselects current deselected selection * * \see deselectGlobalSelection() */ void reselectGlobalSelection(); private: class KisImagePrivate; KisImagePrivate * m_d; }; #endif // KIS_IMAGE_H_ diff --git a/libs/image/kis_math_toolbox.h b/libs/image/kis_math_toolbox.h index 69fb436244..c9fd79257c 100644 --- a/libs/image/kis_math_toolbox.h +++ b/libs/image/kis_math_toolbox.h @@ -1,145 +1,148 @@ /* * This file is part of the KDE project * * Copyright (c) 2005 Cyrille Berger * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_MATH_TOOLBOX_H #define KIS_MATH_TOOLBOX_H #include #include #include #include #include "kis_types.h" #include "kis_paint_device.h" #ifdef _MSC_VER #pragma warning(disable: 4290) // disable "C++ exception specification ignored" warning #endif #if !defined _MSC_VER #pragma GCC diagnostic ignored "-Wcast-align" #endif typedef double(*PtrToDouble)(const quint8*, int); typedef void (*PtrFromDouble)(quint8*, int, double); class KRITAIMAGE_EXPORT KisMathToolbox { public: struct KisFloatRepresentation { KisFloatRepresentation(uint nsize, uint ndepth) : coeffs(new float[nsize*nsize*ndepth]) , size(nsize) , depth(ndepth) { // XXX: Valgrind shows that these are being used without being initialised. for (quint32 i = 0; i < nsize * nsize * ndepth; ++i) { coeffs[i] = 0; } } ~KisFloatRepresentation() { if (coeffs) delete[] coeffs; } float* coeffs; uint size; uint depth; }; typedef KisFloatRepresentation KisWavelet; /** * This function initializes a wavelet structure * @param lay the layer that will be used for the transformation + * @param rect the rectangular for transformation */ inline KisWavelet* initWavelet(KisPaintDeviceSP lay, const QRect&); inline uint fastWaveletTotalSteps(const QRect&); /** * This function reconstruct the layer from the information of a wavelet * @param src layer from which the wavelet will be computed + * @param rect the rectangular for reconstruction * @param buff if set to 0, the buffer will be initialized by the function, * you might want to give a buff to the function if you want to use the same buffer * in transformToWavelet and in untransformToWavelet, use initWavelet to initialize * the buffer */ KisWavelet* fastWaveletTransformation(KisPaintDeviceSP src, const QRect&, KisWavelet* buff = 0); /** * This function reconstruct the layer from the information of a wavelet * @param dst layer on which the wavelet will be untransform + * @param rect the rectangular for reconstruction * @param wav the wavelet * @param buff if set to 0, the buffer will be initialized by the function, * you might want to give a buff to the function if you want to use the same buffer * in transformToWavelet and in untransformToWavelet, use initWavelet to initialize * the buffer */ void fastWaveletUntransformation(KisPaintDeviceSP dst, const QRect&, KisWavelet* wav, KisWavelet* buff = 0); bool getToDoubleChannelPtr(QList cis, QVector& f); bool getFromDoubleChannelPtr(QList cis, QVector& f); double minChannelValue(KoChannelInfo *); double maxChannelValue(KoChannelInfo *); private: void wavetrans(KisWavelet* wav, KisWavelet* buff, uint halfsize); void waveuntrans(KisWavelet* wav, KisWavelet* buff, uint halfsize); /** * This function transform a paint device into a KisFloatRepresentation, this function is colorspace independent, * for Wavelet, Pyramid and FFT the data is always the exact value of the channel stored in a float. */ void transformToFR(KisPaintDeviceSP src, KisFloatRepresentation*, const QRect&); /** * This function transform a KisFloatRepresentation into a paint device, this function is colorspace independent, * for Wavelet, Pyramid and FFT the data is always the exact value of the channel stored in a float. */ void transformFromFR(KisPaintDeviceSP dst, KisFloatRepresentation*, const QRect&); }; inline KisMathToolbox::KisWavelet* KisMathToolbox::initWavelet(KisPaintDeviceSP src, const QRect& rect) { int size; int maxrectsize = (rect.height() < rect.width()) ? rect.width() : rect.height(); for (size = 2; size < maxrectsize; size *= 2) ; qint32 depth = src->colorSpace()->colorChannelCount(); return new KisWavelet(size, depth); } inline uint KisMathToolbox::fastWaveletTotalSteps(const QRect& rect) { int size, steps; int maxrectsize = (rect.height() < rect.width()) ? rect.width() : rect.height(); steps = 0; for (size = 2; size < maxrectsize; size *= 2) steps += size / 2; ; return steps; } #endif diff --git a/libs/image/kis_merge_walker.h b/libs/image/kis_merge_walker.h index 7a6cb842fc..e4b2af6117 100644 --- a/libs/image/kis_merge_walker.h +++ b/libs/image/kis_merge_walker.h @@ -1,92 +1,92 @@ /* * Copyright (c) 2009 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 __KIS_MERGE_WALKER_H #define __KIS_MERGE_WALKER_H #include "kis_types.h" #include "kis_base_rects_walker.h" class KisMergeWalker; typedef KisSharedPtr KisMergeWalkerSP; class KRITAIMAGE_EXPORT KisMergeWalker : public virtual KisBaseRectsWalker { public: /** * NO_FILTHY flag notifies the walker that there should be no (!) * filthy node in the update. It means that the projection() of * the node is already guaranteed to be ready, we just need to * update all the higher-level nodes. Used by KisTransformMask * regeneration code. */ enum Flags { DEFAULT = 0, NO_FILTHY }; KisMergeWalker(QRect cropRect, Flags flags = DEFAULT); ~KisMergeWalker() override; UpdateType type() const override; protected: KisMergeWalker() : m_flags(DEFAULT) {} KisMergeWalker(Flags flags) : m_flags(flags) {} /** - * Begins visiting nodes starting with @startWith. + * Begins visiting nodes starting with @p startWith. * First it climbs to the top of the graph, collecting - * changeRects (it calls @registerChangeRect for every node). + * changeRects (it calls @ref registerChangeRect for every node). * Then it goes down to the bottom collecting needRects * for every branch. */ void startTrip(KisProjectionLeafSP startWith) override; using KisBaseRectsWalker::startTrip; void startTripWithMask(KisProjectionLeafSP filthyMask, KisMergeWalker::Flags flags); private: void startTripImpl(KisProjectionLeafSP startLeaf, Flags flags); private: /** * Visits a node @leaf and goes on crowling * towards the top of the graph, caling visitHigherNode() or * startTrip() one more time. After the top is reached * returns back to the @leaf. */ void visitHigherNode(KisProjectionLeafSP leaf, NodePosition positionToFilthy); /** * Visits a node @leaf and goes on crowling * towards the bottom of the graph, caling visitLowerNode() or * startTrip() one more time. */ void visitLowerNode(KisProjectionLeafSP leaf); private: const Flags m_flags; }; #endif /* __KIS_MERGE_WALKER_H */ diff --git a/libs/image/kis_paint_device.h b/libs/image/kis_paint_device.h index 99e91131a1..969a1181f4 100644 --- a/libs/image/kis_paint_device.h +++ b/libs/image/kis_paint_device.h @@ -1,880 +1,894 @@ /* * Copyright (c) 2002 patrick julien * Copyright (c) 2006 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_PAINT_DEVICE_IMPL_H_ #define KIS_PAINT_DEVICE_IMPL_H_ #include #include #include #include "kis_debug.h" #include #include "kis_types.h" #include "kis_shared.h" #include "kis_default_bounds_base.h" #include class KUndo2Command; class QRect; class QImage; class QPoint; class QString; class QColor; class QIODevice; class KoColor; class KoColorSpace; class KoColorProfile; class KisDataManager; class KisPaintDeviceWriter; class KisKeyframe; class KisRasterKeyframeChannel; class KisPaintDeviceFramesInterface; typedef KisSharedPtr KisDataManagerSP; namespace KritaUtils { enum DeviceCopyMode { CopySnapshot = 0, CopyAllFrames }; } /** * A paint device contains the actual pixel data and offers methods * to read and write pixels. A paint device has an integer x, y position * (it is not positioned on the image with sub-pixel accuracy). * A KisPaintDevice doesn't have any fixed size, the size changes dynamically * when pixels are accessed by an iterator. */ class KRITAIMAGE_EXPORT KisPaintDevice : public QObject , public KisShared { Q_OBJECT public: /** * Create a new paint device with the specified colorspace. * * @param colorSpace the colorspace of this paint device * @param name for debugging purposes */ explicit KisPaintDevice(const KoColorSpace * colorSpace, const QString& name = QString()); /** * Create a new paint device with the specified colorspace. The * parent node will be notified of changes to this paint device. * * @param parent the node that contains this paint device * @param colorSpace the colorspace of this paint device * @param defaultBounds boundaries of the device in case it is empty * @param name for debugging purposes */ KisPaintDevice(KisNodeWSP parent, const KoColorSpace * colorSpace, KisDefaultBoundsBaseSP defaultBounds = KisDefaultBoundsBaseSP(), const QString& name = QString()); /** * Creates a copy of this device. * * If \p copyMode is CopySnapshot, the newly created device clones the * current frame of \p rhs only (default and efficient * behavior). If \p copyFrames is CopyAllFrames, the new device is a deep * copy of the source with all the frames included. */ KisPaintDevice(const KisPaintDevice& rhs, KritaUtils::DeviceCopyMode copyMode = KritaUtils::CopySnapshot, KisNode *newParentNode = 0); ~KisPaintDevice() override; protected: /** * A special constructor for usage in KisPixelSelection. It allows * two paint devices to share a data manager. * * @param explicitDataManager data manager to use inside paint device * @param src source paint device to copy parameters from * @param name for debugging purposes */ KisPaintDevice(KisDataManagerSP explicitDataManager, KisPaintDeviceSP src, const QString& name = QString()); public: /** * Write the pixels of this paint device into the specified file store. */ bool write(KisPaintDeviceWriter &store); /** * Fill this paint device with the pixels from the specified file store. */ bool read(QIODevice *stream); public: /** * set the parent node of the paint device */ void setParentNode(KisNodeWSP parent); /** * set the default bounds for the paint device when * the default pixel is not completely transparent */ void setDefaultBounds(KisDefaultBoundsBaseSP bounds); /** * the default bounds rect of the paint device */ KisDefaultBoundsBaseSP defaultBounds() const; /** * Moves the device to these new coordinates (no incremental move) */ void moveTo(qint32 x, qint32 y); /** * Convenience method for the above. */ virtual void moveTo(const QPoint& pt); /** * Return an X,Y offset of the device in a convenient form */ QPoint offset() const; /** * The X offset of the paint device */ qint32 x() const; /** * The Y offset of the paint device */ qint32 y() const; /** * set the X offset of the paint device */ void setX(qint32 x); /** * set the Y offset of the paint device */ void setY(qint32 y); /** * Retrieve the bounds of the paint device. The size is not exact, * but may be larger if the underlying datamanager works that way. * For instance, the tiled datamanager keeps the extent to the nearest * multiple of 64. * * If default pixel is not transparent, then the actual extent * rect is united with the defaultBounds()->bounds() value * (the size of the image, usually). */ QRect extent() const; /// Convenience method for the above void extent(qint32 &x, qint32 &y, qint32 &w, qint32 &h) const; /** * Get the exact bounds of this paint device. The real solution is * very slow because it does a linear scanline search, but it * uses caching, so calling to this function without changing * the device is quite cheap. * * Exactbounds follows these rules: * *

    *
  • if default pixel is transparent, then exact bounds * of actual pixel data are returned *
  • if default pixel is not transparent, then the union * (defaultBounds()->bounds() | nonDefaultPixelArea()) is * returned *
* \see calculateExactBounds() */ QRect exactBounds() const; /** * Relaxed version of the exactBounds() that can be used in tight * loops. If the exact bounds value is present in the paint * device cache, returns this value. If the cache is invalidated, * returns extent() and tries to recalculate the exact bounds not * faster than once in 1000 ms. */ QRect exactBoundsAmortized() const; /** * Returns exact rectangle of the paint device that contains * non-default pixels. For paint devices with fully transparent * default pixel is equivalent to exactBounds(). * * nonDefaultPixelArea() follows these rules: * *
    *
  • if default pixel is transparent, then exact bounds * of actual pixel data are returned. The same as exactBounds() *
  • if default pixel is not transparent, then calculates the * rectangle of non-default pixels. May be smaller or greater * than image bounds *
* \see calculateExactBounds() */ QRect nonDefaultPixelArea() const; /** * Returns a rough approximation of region covered by device. * For tiled data manager, it region will consist of a number * of rects each corresponding to a tile. */ QRegion region() const; /** * The slow version of region() that searches for exact bounds of * each rectangle in the region */ QRegion regionExact() const; /** * Cut the paint device down to the specified rect. If the crop * area is bigger than the paint device, nothing will happen. */ void crop(qint32 x, qint32 y, qint32 w, qint32 h); /// Convenience method for the above void crop(const QRect & r); /** * Complete erase the current paint device. Its size will become 0. This * does not take the selection into account. */ virtual void clear(); /** * Clear the given rectangle to transparent black. The paint device will expand to * contain the given rect. */ void clear(const QRect & rc); /** * Frees the memory occupied by the pixels containing default * values. The extents() and exactBounds() of the image will * probably also shrink */ void purgeDefaultPixels(); /** * Sets the default pixel. New data will be initialised with this pixel. The pixel is copied: the * caller still owns the pointer and needs to delete it to avoid memory leaks. * If frame ID is given, set default pixel for that frame. Otherwise use active frame. */ void setDefaultPixel(const KoColor &defPixel); /** * Get a pointer to the default pixel. * If the frame parameter is given, get the default pixel of * specified frame. Otherwise use currently active frame. */ KoColor defaultPixel() const; /** * Fill the given rectangle with the given pixel. The paint device will expand to * contain the given rect. */ void fill(const QRect & rc, const KoColor &color); /** * Overloaded function. For legacy purposes only. * Please use fill(const QRect & rc, const KoColor &color) instead */ void fill(qint32 x, qint32 y, qint32 w, qint32 h, const quint8 *fillPixel); public: /** * Prepares the device for fastBitBlt operation. It clears * the device, switches x,y shifts and colorspace if needed. * After this call fastBitBltPossible will return true. * May be used for initialization of temporary devices. */ void prepareClone(KisPaintDeviceSP src); /** * Make this device to become a clone of \a src. It will have the same * x,y shifts, colorspace and will share pixels inside \a rect. * After calling this function: * (this->extent() >= this->exactBounds() == rect). * * Rule of thumb: * * "Use makeCloneFrom() or makeCloneFromRough() if and only if you * are the only owner of the destination paint device and you are * 100% sure no other thread has access to it" */ void makeCloneFrom(KisPaintDeviceSP src, const QRect &rect); /** * Make this device to become a clone of \a src. It will have the same * x,y shifts, colorspace and will share pixels inside \a rect. * Be careful, this function will copy *at least* \a rect * of pixels. Actual copy area will be a bigger - it will * be aligned by tiles borders. So after calling this function: * (this->extent() == this->exactBounds() >= rect). * * Rule of thumb: * * "Use makeCloneFrom() or makeCloneFromRough() if and only if you * are the only owner of the destination paint device and you are * 100% sure no other thread has access to it" */ void makeCloneFromRough(KisPaintDeviceSP src, const QRect &minimalRect); protected: friend class KisPaintDeviceTest; friend class DataReaderThread; /** * Checks whether a src paint device can be used as source * of fast bitBlt operation. The result of the check may * depend on whether color spaces coincide, whether there is * any shift of tiles between the devices and etc. * * WARNING: This check must be done before performing any * fast bitBlt operation! * * \see fastBitBlt * \see fastBitBltRough */ bool fastBitBltPossible(KisPaintDeviceSP src); /** * Clones rect from another paint device. The cloned area will be * shared between both paint devices as much as possible using * copy-on-write. Parts of the rect that cannot be shared * (cross tiles) are deep-copied, * * \see fastBitBltPossible * \see fastBitBltRough */ void fastBitBlt(KisPaintDeviceSP src, const QRect &rect); /** * The same as \ref fastBitBlt() but reads old data */ void fastBitBltOldData(KisPaintDeviceSP src, const QRect &rect); /** * Clones rect from another paint device in a rough and fast way. * All the tiles touched by rect will be shared, between both * devices, that means it will copy a bigger area than was * requested. This method is supposed to be used for bitBlt'ing * into temporary paint devices. * * \see fastBitBltPossible * \see fastBitBlt */ void fastBitBltRough(KisPaintDeviceSP src, const QRect &rect); /** * The same as \ref fastBitBltRough() but reads old data */ void fastBitBltRoughOldData(KisPaintDeviceSP src, const QRect &rect); public: /** * Read the bytes representing the rectangle described by x, y, w, h into * data. If data is not big enough, Krita will gladly overwrite the rest * of your precious memory. * * Since this is a copy, you need to make sure you have enough memory. * * Reading from areas not previously initialized will read the default * pixel value into data but not initialize that region. */ void readBytes(quint8 * data, qint32 x, qint32 y, qint32 w, qint32 h) const; /** * Read the bytes representing the rectangle rect into * data. If data is not big enough, Krita will gladly overwrite the rest * of your precious memory. * * Since this is a copy, you need to make sure you have enough memory. * * Reading from areas not previously initialized will read the default * pixel value into data but not initialize that region. * @param data The address of the memory to receive the bytes read * @param rect The rectangle in the paint device to read from */ void readBytes(quint8 * data, const QRect &rect) const; /** * Copy the bytes in data into the rect specified by x, y, w, h. If the * data is too small or uninitialized, Krita will happily read parts of * memory you never wanted to be read. * * If the data is written to areas of the paint device not previously initialized, * the paint device will grow. */ void writeBytes(const quint8 * data, qint32 x, qint32 y, qint32 w, qint32 h); /** * Copy the bytes in data into the rectangle rect. If the * data is too small or uninitialized, Krita will happily read parts of * memory you never wanted to be read. * * If the data is written to areas of the paint device not previously initialized, * the paint device will grow. * @param data The address of the memory to write bytes from * @param rect The rectangle in the paint device to write to */ void writeBytes(const quint8 * data, const QRect &rect); /** * Copy the bytes in the paint device into a vector of arrays of bytes, * where the number of arrays is the number of channels in the * paint device. If the specified area is larger than the paint * device's extent, the default pixel will be read. */ QVector readPlanarBytes(qint32 x, qint32 y, qint32 w, qint32 h) const; /** * Write the data in the separate arrays to the channes. If there * are less vectors than channels, the remaining channels will not * be copied. If any of the arrays points to 0, the channel in * that location will not be touched. If the specified area is * larger than the paint device, the paint device will be * extended. There are no guards: if the area covers more pixels * than there are bytes in the arrays, krita will happily fill * your paint device with areas of memory you never wanted to be * read. Krita may also crash. * * XXX: what about undo? */ void writePlanarBytes(QVector planes, qint32 x, qint32 y, qint32 w, qint32 h); /** * Converts the paint device to a different colorspace * * @return a command that can be used to undo the conversion. */ KUndo2Command* convertTo(const KoColorSpace * dstColorSpace, KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags = KoColorConversionTransformation::internalConversionFlags()); /** * Changes the profile of the colorspace of this paint device to the given * profile. If the given profile is 0, nothing happens. */ bool setProfile(const KoColorProfile * profile); /** * Fill this paint device with the data from image; starting at (offsetX, offsetY) - * @param srcProfileName name of the RGB profile to interpret the image as. 0 is interpreted as sRGB + * @param image the image + * @param profile name of the RGB profile to interpret the image as. 0 is interpreted as sRGB + * @param offsetX x offset + * @param offsetY y offset */ void convertFromQImage(const QImage& image, const KoColorProfile *profile, qint32 offsetX = 0, qint32 offsetY = 0); /** * Create an RGBA QImage from a rectangle in the paint device. * + * @param dstProfile RGB profile to use in conversion. May be 0, in which + * case it's up to the color strategy to choose a profile (most + * like sRGB). * @param x Left coordinate of the rectangle * @param y Top coordinate of the rectangle * @param w Width of the rectangle in pixels * @param h Height of the rectangle in pixels - * @param dstProfile RGB profile to use in conversion. May be 0, in which - * case it's up to the color strategy to choose a profile (most - * like sRGB). + * @param renderingIntent Rendering intent + * @param conversionFlags Conversion flags */ QImage convertToQImage(const KoColorProfile *dstProfile, qint32 x, qint32 y, qint32 w, qint32 h, KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags = KoColorConversionTransformation::internalConversionFlags()) const; /** * Overridden method for convenience */ QImage convertToQImage(const KoColorProfile *dstProfile, const QRect &rc, KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags = KoColorConversionTransformation::internalConversionFlags()) const; /** * Create an RGBA QImage from a rectangle in the paint device. The * rectangle is defined by the parent image's bounds. * * @param dstProfile RGB profile to use in conversion. May be 0, in which * case it's up to the color strategy to choose a profile (most * like sRGB). + * @param renderingIntent Rendering intent + * @param conversionFlags Conversion flags */ QImage convertToQImage(const KoColorProfile * dstProfile, KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags = KoColorConversionTransformation::internalConversionFlags()) const; /** * Creates a paint device thumbnail of the paint device, retaining * the aspect ratio. The width and height of the returned device * won't exceed \p maxw and \p maxw, but they may be smaller. * - * @param maxw: maximum width - * @param maxh: maximum height - * @param rect: only this rect will be used for the thumbnail + * @param w maximum width + * @param h maximum height + * @param rect only this rect will be used for the thumbnail + * @param outputRect output rectangle * */ KisPaintDeviceSP createThumbnailDevice(qint32 w, qint32 h, QRect rect = QRect(), QRect outputRect = QRect()) const; KisPaintDeviceSP createThumbnailDeviceOversampled(qint32 w, qint32 h, qreal oversample, QRect rect = QRect(), QRect outputRect = QRect()) const; /** * Creates a thumbnail of the paint device, retaining the aspect ratio. * The width and height of the returned QImage won't exceed \p maxw and \p maxw, but they may be smaller. * The colors are not corrected for display! * * @param maxw: maximum width * @param maxh: maximum height * @param rect: only this rect will be used for the thumbnail * @param oversample: ratio used for antialiasing + * @param renderingIntent Rendering intent + * @param conversionFlags Conversion flags */ QImage createThumbnail(qint32 maxw, qint32 maxh, QRect rect, qreal oversample = 1, KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags = KoColorConversionTransformation::internalConversionFlags()); /** * Cached version of createThumbnail(qint32 maxw, qint32 maxh, const KisSelection *selection, QRect rect) */ QImage createThumbnail(qint32 maxw, qint32 maxh, qreal oversample = 1, KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags = KoColorConversionTransformation::internalConversionFlags()); /** * Fill c and opacity with the values found at x and y. * * The color values will be transformed from the profile of * this paint device to the display profile. * * @return true if the operation was successful. */ bool pixel(qint32 x, qint32 y, QColor *c) const; /** * Fill kc with the values found at x and y. This method differs * from the above in using KoColor, which can be of any colorspace * * The color values will be transformed from the profile of * this paint device to the display profile. * * @return true if the operation was successful. */ bool pixel(qint32 x, qint32 y, KoColor * kc) const; /** * Set the specified pixel to the specified color. Note that this * bypasses KisPainter. the PaintDevice is here used as an equivalent * to QImage, not QPixmap. This means that this is not undoable; also, * there is no compositing with an existing value at this location. * * The color values will be transformed from the display profile to * the paint device profile. * * Note that this will use 8-bit values and may cause a significant * degradation when used on 16-bit or hdr quality images. * * @return true if the operation was successful */ bool setPixel(qint32 x, qint32 y, const QColor& c); /// Convenience method for the above bool setPixel(qint32 x, qint32 y, const KoColor& kc); /** * @return the colorspace of the pixels in this paint device */ const KoColorSpace* colorSpace() const; /** * There is quite a common technique in Krita. It is used in * cases, when we want to paint something over a paint device * using the composition, opacity or selection. E.g. painting a * dab in a paint op, filling the selection in the Fill Tool. * Such work is usually done in the following way: * * 1) Create a paint device * * 2) Fill it with the desired color or data * * 3) Create a KisPainter and set all the properties of the * transaction: selection, compositeOp, opacity and etc. * * 4) Paint a newly created paint device over the destination * device. * * The following two methods (createCompositionSourceDevice() or * createCompositionSourceDeviceFixed())should be used for the * accomplishing the step 1). The point is that the desired color * space of the temporary device may not coincide with the color * space of the destination. That is the case, for example, for * the alpha8() colorspace used in the selections. So for such * devices the temporary target would have a different (grayscale) * color space. * * So there are two rules of thumb: * * 1) If you need a temporary device which you are going to fill * with some data and then paint over the paint device, create * it with either createCompositionSourceDevice() or * createCompositionSourceDeviceFixed(). * * 2) Do *not* expect that the color spaces of the destination and * the temporary device would coincide. If you need to copy a * single pixel from one device to another, you can use * KisCrossDeviceColorPicker class, that will handle all the * necessary conversions for you. * * \see createCompositionSourceDeviceFixed() * \see compositionSourceColorSpace() * \see KisCrossDeviceColorPicker * \see KisCrossDeviceColorPickerInt */ KisPaintDeviceSP createCompositionSourceDevice() const; /** * The same as createCompositionSourceDevice(), but initializes the * newly created device with the content of \p cloneSource * * \see createCompositionSourceDevice() */ KisPaintDeviceSP createCompositionSourceDevice(KisPaintDeviceSP cloneSource) const; /** * The same as createCompositionSourceDevice(), but initializes * the newly created device with the *rough* \p roughRect of * \p cloneSource. * * "Rough rect" means that it may copy a bit more than * requested. It is expected that the caller will not use the area * outside \p roughRect. * * \see createCompositionSourceDevice() */ KisPaintDeviceSP createCompositionSourceDevice(KisPaintDeviceSP cloneSource, const QRect roughRect) const; /** * This is a convenience method for createCompositionSourceDevice() * * \see createCompositionSourceDevice() */ KisFixedPaintDeviceSP createCompositionSourceDeviceFixed() const; /** * This is a lowlevel method for the principle used in * createCompositionSourceDevice(). In most of the cases the paint * device creation methods should be used instead of this function. * * \see createCompositionSourceDevice() * \see createCompositionSourceDeviceFixed() */ virtual const KoColorSpace* compositionSourceColorSpace() const; /** * @return the internal datamanager that keeps the pixels. */ KisDataManagerSP dataManager() const; /** * Replace the pixel data, color strategy, and profile. */ void setDataManager(KisDataManagerSP data, const KoColorSpace * colorSpace = 0); /** * Return the number of bytes a pixel takes. */ quint32 pixelSize() const; /** * Return the number of channels a pixel takes */ quint32 channelCount() const; /** * Create a keyframe channel for the content on this device. * @param id identifier for the channel - * @param node the parent node for the channel * @return keyframe channel or 0 if there is not one */ KisRasterKeyframeChannel *createKeyframeChannel(const KoID &id); KisRasterKeyframeChannel* keyframeChannel() const; /** * An interface to modify/load/save frames stored inside this device */ KisPaintDeviceFramesInterface* framesInterface(); public: /** * Add the specified rect to the parent layer's set of dirty rects * (if there is a parent layer) */ void setDirty(const QRect & rc); /** * Add the specified region to the parent layer's dirty region * (if there is a parent layer) */ void setDirty(const QRegion & region); /** * Set the parent layer completely dirty, if this paint device has * as parent layer. */ void setDirty(); void setDirty(const QVector rects); /** * Called by KisTransactionData when it thinks current time should * be changed. And the requests is forwarded to the image if * needed. */ void requestTimeSwitch(int time); /** * \return a sequence number corresponding to the current paint * device state. Every time the paint device is changed, * the sequence number is increased */ int sequenceNumber() const; void estimateMemoryStats(qint64 &imageData, qint64 &temporaryData, qint64 &lodData) const; public: KisHLineIteratorSP createHLineIteratorNG(qint32 x, qint32 y, qint32 w); KisHLineConstIteratorSP createHLineConstIteratorNG(qint32 x, qint32 y, qint32 w) const; KisVLineIteratorSP createVLineIteratorNG(qint32 x, qint32 y, qint32 h); KisVLineConstIteratorSP createVLineConstIteratorNG(qint32 x, qint32 y, qint32 h) const; KisRandomAccessorSP createRandomAccessorNG(qint32 x, qint32 y); KisRandomConstAccessorSP createRandomConstAccessorNG(qint32 x, qint32 y) const; /** * Create an iterator that will "artificially" extend the paint device with the * value of the border when trying to access values outside the range of data. * - * @param rc indicates the rectangle that truly contains data + * @param x x of top left corner + * @param y y of top left corner + * @param w width of the border + * @param _dataWidth indicates the rectangle that truly contains data */ KisRepeatHLineConstIteratorSP createRepeatHLineConstIterator(qint32 x, qint32 y, qint32 w, const QRect& _dataWidth) const; /** * Create an iterator that will "artificially" extend the paint device with the * value of the border when trying to access values outside the range of data. * - * @param rc indicates the rectangle that truly contains data + * @param x x of top left corner + * @param y y of top left corner + * @param h height of the border + * @param _dataWidth indicates the rectangle that truly contains data */ KisRepeatVLineConstIteratorSP createRepeatVLineConstIterator(qint32 x, qint32 y, qint32 h, const QRect& _dataWidth) const; /** * This function create a random accessor which can easily access to sub pixel values. - * @param selection an up-to-date selection that has the same origin as the paint device */ KisRandomSubAccessorSP createRandomSubAccessor() const; /** Clear the selected pixels from the paint device */ void clearSelection(KisSelectionSP selection); Q_SIGNALS: void profileChanged(const KoColorProfile * profile); void colorSpaceChanged(const KoColorSpace *colorspace); public: friend class PaintDeviceCache; /** * Caclculates exact bounds of the device. Used internally * by a transparent caching system. The solution is very slow * because it does a linear scanline search. So the complexity * is n*n at worst. * * \see exactBounds(), nonDefaultPixelArea() */ QRect calculateExactBounds(bool nonDefaultOnly) const; public: struct MemoryReleaseObject : public QObject { ~MemoryReleaseObject() override; }; static MemoryReleaseObject* createMemoryReleaseObject(); public: struct LodDataStruct { virtual ~LodDataStruct(); }; QRegion regionForLodSyncing() const; LodDataStruct* createLodDataStruct(int lod); void updateLodDataStruct(LodDataStruct *dst, const QRect &srcRect); void uploadLodDataStruct(LodDataStruct *dst); void generateLodCloneDevice(KisPaintDeviceSP dst, const QRect &originalRect, int lod); void setProjectionDevice(bool value); void tesingFetchLodDevice(KisPaintDeviceSP targetDevice); private: KisPaintDevice& operator=(const KisPaintDevice&); void init(const KoColorSpace *colorSpace, KisDefaultBoundsBaseSP defaultBounds, KisNodeWSP parent, const QString& name); // Only KisPainter is allowed to have access to these low-level methods friend class KisPainter; /** * Return a vector with in order the size in bytes of the channels * in the colorspace of this paint device. */ QVector channelSizes() const; void emitColorSpaceChanged(); void emitProfileChanged(); private: friend class KisPaintDeviceFramesInterface; protected: friend class KisSelectionTest; KisNodeWSP parentNode() const; private: struct Private; Private * const m_d; }; #endif // KIS_PAINT_DEVICE_IMPL_H_ diff --git a/libs/image/kis_paint_device_debug_utils.h b/libs/image/kis_paint_device_debug_utils.h index defb556dd8..85c5f6582d 100644 --- a/libs/image/kis_paint_device_debug_utils.h +++ b/libs/image/kis_paint_device_debug_utils.h @@ -1,67 +1,67 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 __KIS_PAINT_DEVICE_DEBUG_UTILS_H #define __KIS_PAINT_DEVICE_DEBUG_UTILS_H class QRect; class QString; #include #include void KRITAIMAGE_EXPORT kis_debug_save_device_incremental(KisPaintDeviceSP device, int i, const QRect &rc, const QString &suffix, const QString &prefix); /** * Saves the paint device incrementally. Put this macro into a * function that is called several times and you'll have as many * separate dump files as the number of times the function was * called. That is very convenient for debugging canvas updates: * adding this macro will let you track the whole history of updates. * - * The files are saved with pattern: _.png + * The files are saved with pattern: \_\.png */ #define KIS_DUMP_DEVICE_1(device, rc, suffix) \ do { \ static int i = -1; i++; \ kis_debug_save_device_incremental((device), i, (rc), (suffix), QString()); \ } while(0) /** * Saves the paint device incrementally. Put this macro into a * function that is called several times and you'll have as many * separate dump files as the number of times the function was * called. That is very convenient for debugging canvas updates: * adding this macro will let you track the whole history of updates. * * The \p prefix parameter makes it easy to sort out dumps from * different functions. * - * The files are saved with pattern: __.png + * The files are saved with pattern: \_\_\.png */ #define KIS_DUMP_DEVICE_2(device, rc, suffix, prefix) \ do { \ static int i = -1; i++; \ kis_debug_save_device_incremental((device), i, (rc), (suffix), (prefix)); \ } while(0) #endif /* __KIS_PAINT_DEVICE_DEBUG_UTILS_H */ diff --git a/libs/image/kis_paint_device_frames_interface.h b/libs/image/kis_paint_device_frames_interface.h index bf5f6f33bb..66e9493512 100644 --- a/libs/image/kis_paint_device_frames_interface.h +++ b/libs/image/kis_paint_device_frames_interface.h @@ -1,154 +1,155 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 __KIS_PAINT_DEVICE_FRAMES_INTERFACE_H #define __KIS_PAINT_DEVICE_FRAMES_INTERFACE_H #include "kis_types.h" #include "kritaimage_export.h" class KisPaintDeviceData; class KisPaintDeviceWriter; class KisDataManager; typedef KisSharedPtr KisDataManagerSP; class KRITAIMAGE_EXPORT KisPaintDeviceFramesInterface { public: KisPaintDeviceFramesInterface(KisPaintDevice *parentDevice); /** * Return a list of IDs for the frames contained in this paint device * @return list of frame IDs */ QList frames(); /** * Creates a new frame on the device and returns an identifier for it. * @return frame id of the newly created frame */ int createFrame(bool copy, int copySrc, const QPoint &offset, KUndo2Command *parentCommand); /** * Delete the frame with given id * @param frame frame ID + * @param parentCommand parent command */ void deleteFrame(int frame, KUndo2Command *parentCommand); /** * Copy the given frame into the target device * @param frameId ID of the frame to be copied * @param targetDevice paint device to copy to */ void fetchFrame(int frameId, KisPaintDeviceSP targetDevice); /** * Copy the given paint device contents into the specified frame - * @param dstFrameId ID of the frame to be overwritten (must exist) * @param srcFrameId ID of the frame to copy from (must exist) - * @param sourceDevice paint device to copy from + * @param dstFrameId ID of the frame to be overwritten (must exist) + * @param srcDevice paint device to copy from */ void uploadFrame(int srcFrameId, int dstFrameId, KisPaintDeviceSP srcDevice); /** * Copy the given paint device contents into the specified frame * @param dstFrameId ID of the frame to be overwritten (must exist) - * @param sourceDevice paint device to copy from + * @param srcDevice paint device to copy from */ void uploadFrame(int dstFrameId, KisPaintDeviceSP srcDevice); /** * @return extent() of \p frameId */ QRect frameBounds(int frameId); /** * @return offset of a data on \p frameId */ QPoint frameOffset(int frameId) const; /** * Sets default pixel for \p frameId */ void setFrameDefaultPixel(const KoColor &defPixel, int frameId); /** * @return default pixel for \p frameId */ KoColor frameDefaultPixel(int frameId) const; /** * Write a \p frameId onto \p store */ bool writeFrame(KisPaintDeviceWriter &store, int frameId); /** * Loads content of a \p frameId from \p stream. * * NOTE: the frame must be created manually with createFrame() * beforehand! */ bool readFrame(QIODevice *stream, int frameId); /** * Returns frameId of the currently active frame. * Should be used by Undo framework only! */ int currentFrameId() const; /** * Returns the data manager of the specified frame. * Should be used by Undo framework only! */ KisDataManagerSP frameDataManager(int frameId) const; /** * Resets the cache object associated with the frame. * Should be used by Undo framework only! */ void invalidateFrameCache(int frameId); /** * Sets the offset for \p frameId. * Should be used by Undo framework only! */ void setFrameOffset(int frameId, const QPoint &offset); struct TestingDataObjects { typedef KisPaintDeviceData Data; typedef QHash FramesHash; Data *m_data; Data *m_lodData; Data *m_externalFrameData; FramesHash m_frames; Data *m_currentData; }; TestingDataObjects testingGetDataObjects() const; QList testingGetDataObjectsList() const; private: KisPaintDevice *q; }; #endif /* __KIS_PAINT_DEVICE_FRAMES_INTERFACE_H */ diff --git a/libs/image/kis_painter.h b/libs/image/kis_painter.h index 97764594d8..f2c5defa0d 100644 --- a/libs/image/kis_painter.h +++ b/libs/image/kis_painter.h @@ -1,880 +1,883 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004 Clarence Dang * Copyright (c) 2008-2010 Lukáš Tvrdý * Copyright (c) 2010 José Luis Vergara Toloza * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_PAINTER_H_ #define KIS_PAINTER_H_ #include #include #include #include #include #include #include "kundo2magicstring.h" #include "kis_types.h" #include #include class QPen; class KUndo2Command; class QRect; class QRectF; class QBitArray; class QPainterPath; class KoUpdater; class KoColor; class KoCompositeOp; class KisUndoAdapter; class KisPostExecutionUndoAdapter; class KisTransaction; class KisPaintInformation; class KisPaintOp; class KisDistanceInformation; struct KisRenderedDab; class KisRunnableStrokeJobsInterface; /** * KisPainter contains the graphics primitives necessary to draw on a * KisPaintDevice. This is the same kind of abstraction as used in Qt * itself, where you have QPainter and QPaintDevice. * * However, KisPainter works on a tiled image and supports different * color models, and that's a lot more complicated. * * KisPainter supports transactions that can group various paint operations * in one undoable step. * * For more complex operations, you might want to have a look at the subclasses * of KisPainter: KisConvolutionPainter, KisFillPainter and KisGradientPainter * * KisPainter sets a number of default values, like COMPOSITE_OVER for compositeop, * OPACITY_OPAQUE for opacity and no selection for selection. */ class KRITAIMAGE_EXPORT KisPainter { public: /// Construct painter without a device KisPainter(); /// Construct a painter, and begin painting on the device KisPainter(KisPaintDeviceSP device); /// Construct a painter, and begin painting on the device. All actions will be masked by the given selection. KisPainter(KisPaintDeviceSP device, KisSelectionSP selection); virtual ~KisPainter(); public: static void copyAreaOptimized(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &originalSrcRect); static void copyAreaOptimizedOldData(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &originalSrcRect); static void copyAreaOptimized(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &originalSrcRect, KisSelectionSP selection); static KisPaintDeviceSP convertToAlphaAsAlpha(KisPaintDeviceSP src); static KisPaintDeviceSP convertToAlphaAsGray(KisPaintDeviceSP src); static bool checkDeviceHasTransparency(KisPaintDeviceSP dev); /** * Start painting on the specified device. Not undoable. */ void begin(KisPaintDeviceSP device); /** * Start painting on the specified paint device. All actions will be masked by the given selection. */ void begin(KisPaintDeviceSP device, KisSelectionSP selection); /** * Finish painting on the current device */ void end(); /** * If set, the painter action is cancelable, if the action supports that. */ void setProgress(KoUpdater * progressUpdater); /// Begin an undoable paint operation void beginTransaction(const KUndo2MagicString& transactionName = KUndo2MagicString(),int timedID = -1); /// Cancel all the changes made by the painter void revertTransaction(); /// Finish the undoable paint operation void endTransaction(KisUndoAdapter *undoAdapter); /** * Finish transaction and load it to a special adapter for strokes */ void endTransaction(KisPostExecutionUndoAdapter *undoAdapter); /** * Finishes a transaction and returns a pointer to its undo command */ KUndo2Command* endAndTakeTransaction(); /** * Finish the transaction and delete it's undo information. * NOTE: Be careful, because all the previous transactions * will become non-undoable after execution of this method. */ void deleteTransaction(); /// continue a transaction started somewhere else void putTransaction(KisTransaction* transaction); /// take transaction out of the reach of KisPainter KisTransaction* takeTransaction(); /// Returns the current paint device. const KisPaintDeviceSP device() const; KisPaintDeviceSP device(); /** * Blast a region of srcWidth @param srcWidth and srcHeight @param srcHeight from @param * srcDev onto the current paint device. @param srcX and @param srcY set the x and y * positions of the origin top-left corner, @param dstX and @param dstY those of * the destination. * Any pixel read outside the limits of @param srcDev will return the * default pixel, this is a property of \ref KisPaintDevice. * * @param dstX the destination x-coordinate * @param dstY the destination y-coordinate * @param srcDev the source device * @param srcX the source x-coordinate * @param srcY the source y-coordinate * @param srcWidth the width of the region to be manipulated * @param srcHeight the height of the region to be manipulated */ void bitBlt(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight); /** * Convenience method that uses QPoint and QRect. * - * @param pos the destination coordinate, it replaces @param dstX and @param dstY. + * @param pos the destination coordinate, it replaces @p dstX and @p dstY. * @param srcDev the source device. - * @param srcRect the rectangle describing the area to blast from @param srcDev into the current paint device. - * @param srcRect replaces @param srcX, @param srcY, @param srcWidth and @param srcHeight. + * @param srcRect the rectangle describing the area to blast from @p srcDev into the current paint device. + * @p srcRect replaces @p srcX, @p srcY, @p srcWidth and @p srcHeight. * */ void bitBlt(const QPoint & pos, const KisPaintDeviceSP srcDev, const QRect & srcRect); /** * The same as @ref bitBlt() but reads data from oldData() part of the device * * @param dstX the destination x-coordinate * @param dstY the destination y-coordinate * @param srcDev the source device * @param srcX the source x-coordinate * @param srcY the source y-coordinate * @param srcWidth the width of the region to be manipulated * @param srcHeight the height of the region to be manipulated */ void bitBltOldData(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight); /** * Convenience method that uses QPoint and QRect. * - * @param pos the destination coordinate, it replaces @param dstX and @param dstY. + * @param pos the destination coordinate, it replaces @p dstX and @p dstY. * @param srcDev the source device. * @param srcRect the rectangle describing the area to blast from @param srcDev into the current paint device. - * @param srcRect replaces @param srcX, @param srcY, @param srcWidth and @param srcHeight. + * @p srcRect replaces @p srcX, @p srcY, @p srcWidth and @p srcHeight. * */ void bitBltOldData(const QPoint & pos, const KisPaintDeviceSP srcDev, const QRect & srcRect); /** * Blasts a @param selection of srcWidth @param srcWidth and srcHeight @param srcHeight * of @param srcDev on the current paint device. There is parameters * to control where the area begins in each distinct device, explained below. * @param selection can be used as a mask to shape @param srcDev to * something interesting in the same step it is rendered to the current * paint device. @param selection 's colorspace must be alpha8 (the * colorspace for selections/transparency), the rectangle formed by * @param selX, @param selY, @param srcWidth and @param srcHeight must not go * beyond its limits, and they must be different from zero. * @param selection and KisPainter's selection (the user selection) are * fused together through the composite operation COMPOSITE_MULT. * Any pixel read outside the limits of @param srcDev will return the * default pixel, this is a property of \ref KisPaintDevice. * * @param dstX the destination x-coordinate * @param dstY the destination y-coordinate * @param srcDev the source device * @param selection the custom selection to apply on the source device * @param selX the selection x-coordinate * @param selY the selection y-coordinate * @param srcX the source x-coordinate * @param srcY the source y-coordinate * @param srcWidth the width of the region to be manipulated * @param srcHeight the height of the region to be manipulated * */ void bitBltWithFixedSelection(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, const KisFixedPaintDeviceSP selection, qint32 selX, qint32 selY, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight); /** - * Convenience method that assumes @param selX, @param selY, @param srcX and @param srcY are - * equal to 0. Best used when @param selection and the desired area of @param srcDev have exactly + * Convenience method that assumes @p selX, @p selY, @p srcX and @p srcY are + * equal to 0. Best used when @p selection and the desired area of @p srcDev have exactly * the same dimensions and are specially made for each other. * * @param dstX the destination x-coordinate * @param dstY the destination y-coordinate * @param srcDev the source device * @param selection the custom selection to apply on the source device * @param srcWidth the width of the region to be manipulated * @param srcHeight the height of the region to be manipulated */ void bitBltWithFixedSelection(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, const KisFixedPaintDeviceSP selection, qint32 srcWidth, qint32 srcHeight); /** - * Blast a region of srcWidth @param srcWidth and srcHeight @param srcHeight from @param srcDev onto the current - * paint device. @param srcX and @param srcY set the x and y positions of the - * origin top-left corner, @param dstX and @param dstY those of the destination. - * @param srcDev is a \ref KisFixedPaintDevice: this means that @param srcDev must have the same + * Blast a region of srcWidth @p srcWidth and srcHeight @p srcHeight from @p srcDev onto the current + * paint device. @p srcX and @p srcY set the x and y positions of the + * origin top-left corner, @p dstX and @p dstY those of the destination. + * @p srcDev is a @ref KisFixedPaintDevice : this means that @p srcDev must have the same * colorspace as the destination device. * * @param dstX the destination x-coordinate * @param dstY the destination y-coordinate * @param srcDev the source device * @param srcX the source x-coordinate * @param srcY the source y-coordinate * @param srcWidth the width of the region to be manipulated * @param srcHeight the height of the region to be manipulated */ void bltFixed(qint32 dstX, qint32 dstY, const KisFixedPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight); /** * Render the area \p rc from \p srcDevices on the destination device. * If \p rc doesn't cross the device's rect, then the device is not * rendered at all. */ void bltFixed(const QRect &rc, const QList allSrcDevices); /** * Convenience method that uses QPoint and QRect. * - * @param pos the destination coordinate, it replaces @param dstX and @param dstY. + * @param pos the destination coordinate, it replaces @p dstX and @p dstY. * @param srcDev the source device. - * @param srcRect the rectangle describing the area to blast from @param srcDev into the current paint device. - * @param srcRect replaces @param srcX, @param srcY, @param srcWidth and @param srcHeight. + * @param srcRect the rectangle describing the area to blast from @p srcDev into the current paint device. + * @param srcRect replaces @p srcX, @p srcY, @p srcWidth and @p srcHeight. * */ void bltFixed(const QPoint & pos, const KisFixedPaintDeviceSP srcDev, const QRect & srcRect); /** - * Blasts a @param selection of srcWidth @param srcWidth and srcHeight @param srcHeight - * of @param srcDev on the current paint device. There is parameters to control - * the top-left corner of the area in each respective paint device (@param dstX, - * @param dstY, @param srcX, @param srcY). - * @param selection can be used as a mask to shape @param srcDev to something + * Blasts a @p selection of srcWidth @p srcWidth and srcHeight @p srcHeight + * of @p srcDev on the current paint device. There is parameters to control + * the top-left corner of the area in each respective paint device (@p dstX, + * @p dstY, @p srcX, @p srcY). + * @p selection can be used as a mask to shape @p srcDev to something * interesting in the same step it is rendered to the current paint device. - * @param srcDev is a \ref KisFixedPaintDevice: this means that @param srcDev + * @p srcDev is a @ref KisFixedPaintDevice : this means that @p srcDev * must have the same colorspace as the destination device. - * @param selection 's colorspace must be alpha8 (the colorspace for + * @p selection 's colorspace must be alpha8 (the colorspace for * selections/transparency). * The rectangle formed by the respective top-left coordinates of each device - * and @param srcWidth and @param srcHeight must not go beyond their limits, and + * and @p srcWidth and @p srcHeight must not go beyond their limits, and * they must be different from zero. - * @param selection and KisPainter's selection (the user selection) are + * @p selection and KisPainter's selection (the user selection) are * fused together through the composite operation COMPOSITE_MULT. * * @param dstX the destination x-coordinate * @param dstY the destination y-coordinate * @param srcDev the source device * @param selection the selection stored in fixed device * @param selX the selection x-coordinate * @param selY the selection y-coordinate * @param srcX the source x-coordinate * @param srcY the source y-coordinate * @param srcWidth the width of the region to be manipulated * @param srcHeight the height of the region to be manipulated */ void bltFixedWithFixedSelection(qint32 dstX, qint32 dstY, const KisFixedPaintDeviceSP srcDev, const KisFixedPaintDeviceSP selection, qint32 selX, qint32 selY, qint32 srcX, qint32 srcY, quint32 srcWidth, quint32 srcHeight); /** - * Convenience method that assumes @param selX, @param selY, @param srcX and @param srcY are - * equal to 0. Best used when @param selection and @param srcDev have exactly the same + * Convenience method that assumes @p selX, @p selY, @p srcX and @p srcY are + * equal to 0. Best used when @p selection and @p srcDev have exactly the same * dimensions and are specially made for each other. * * @param dstX the destination x-coordinate * @param dstY the destination y-coordinate * @param srcDev the source device * @param selection the custom selection to apply on the source device * @param srcWidth the width of the region to be manipulated * @param srcHeight the height of the region to be manipulated */ void bltFixedWithFixedSelection(qint32 dstX, qint32 dstY, const KisFixedPaintDeviceSP srcDev, const KisFixedPaintDeviceSP selection, quint32 srcWidth, quint32 srcHeight); /** - * fills a region of width @param width and height @param height of the current - * paint device with the color @param color. @param x and @param y set the x and y positions of the + * fills a region of width @p width and height @p height of the current + * paint device with the color @p color. @p x and @p y set the x and y positions of the * origin top-left corner. * * @param x the destination x-coordinate * @param y the destination y-coordinate * @param width the width of the region to be manipulated * @param height the height of the region to be manipulated * @param color the color the area is filled with */ void fill(qint32 x, qint32 y, qint32 width, qint32 height, const KoColor& color); /** * First you need to setup the painter with setMirrorInformation, * then these set of methods provide way to render the devices mirrored * according the axesCenter vertically or horizontally or both. * * @param rc rectangle area covered by dab * @param dab this device will be mirrored in-place, it means that it will be changed */ void renderMirrorMask(QRect rc, KisFixedPaintDeviceSP dab); void renderMirrorMask(QRect rc, KisFixedPaintDeviceSP dab, KisFixedPaintDeviceSP mask); void renderMirrorMask(QRect rc, KisPaintDeviceSP dab); void renderMirrorMask(QRect rc, KisPaintDeviceSP dab, int sx, int sy, KisFixedPaintDeviceSP mask); /** * Convenience method for renderMirrorMask(), allows to choose whether * we need to preserve out dab or do the transformations in-place. * * @param rc rectangle area covered by dab * @param dab the device to render * @param preserveDab states whether a temporary device should be * created to do the transformations */ void renderMirrorMaskSafe(QRect rc, KisFixedPaintDeviceSP dab, bool preserveDab); /** * Convenience method for renderMirrorMask(), allows to choose whether * we need to preserve our fixed mask or do the transformations in-place. * - * @param rc rectangle area covered by dab + * @param rc rectangular area covered by dab * @param dab the device to render + * @param sx x coordinate of the top left corner of the area + * @param sy y coordinate of the top left corner of the area * @param mask mask to use for rendering * @param preserveMask states whether a temporary device should be * created to do the transformations */ void renderMirrorMaskSafe(QRect rc, KisPaintDeviceSP dab, int sx, int sy, KisFixedPaintDeviceSP mask, bool preserveMask); /** * A complex method that re-renders a dab on an \p rc area. * The \p rc area and all the dedicated mirroring areas are cleared * before the painting, so this method should be used by paintops * which do not update the canvas incrementally, but instead * regenerate some internal cache \p dab with the COMPOSITE_COPY op. * * \see KisExperimentPaintOp */ void renderDabWithMirroringNonIncremental(QRect rc, KisPaintDeviceSP dab); /** * @return true if the painter has some rects marked as dirty * @see takeDirtyRegion(), addDirtyRect() */ bool hasDirtyRegion() const; /** * The methods in this class do not tell the paintdevice to update, but they calculate the * dirty area. This method returns this dirty area and resets it. */ QVector takeDirtyRegion(); /** * Paint a line that connects the dots in points */ void paintPolyline(const QVector &points, int index = 0, int numPoints = -1); /** * Draw a line between pos1 and pos2 using the currently set brush and color. * If savedDist is less than zero, the brush is painted at pos1 before being * painted along the line using the spacing setting. * @return the drag distance, that is the remains of the distance between p1 and p2 not covered * because the currently set brush has a spacing greater than that distance. */ void paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance); /** - * Draw a Bezier curve between pos1 and pos2 using control points 1 and 2. + * Draw a Bezier curve between @p pi1 and @p pi2 using control points @p control1 and @p control2. * If savedDist is less than zero, the brush is painted at pos1 before being * painted along the curve using the spacing setting. - * @return the drag distance, that is the remains of the distance between p1 and p2 not covered + * @return the drag distance, that is the remains of the distance between @p pi1 and @p pi2 not covered * because the currently set brush has a spacing greater than that distance. */ void paintBezierCurve(const KisPaintInformation &pi1, const QPointF &control1, const QPointF &control2, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance); /** * Fill the given vector points with the points needed to draw the Bezier curve between - * pos1 and pos2 using control points 1 and 2, excluding the final pos2. + * @p pos1 and @p pos2 using control points @p control1 and @p control2, excluding the final pos2. */ void getBezierCurvePoints(const QPointF &pos1, const QPointF &control1, const QPointF &control2, const QPointF &pos2, vQPointF& points) const; /** * Paint a rectangle. * @param rect the rectangle to paint. */ void paintRect(const QRectF &rect); /** * Paint a rectangle. * * @param x x coordinate of the top-left corner * @param y y coordinate of the top-left corner * @param w the rectangle width * @param h the rectangle height */ void paintRect(const qreal x, const qreal y, const qreal w, const qreal h); /** * Paint the ellipse that fills the given rectangle. * * @param rect the rectangle containing the ellipse to paint. */ void paintEllipse(const QRectF &rect); /** * Paint the ellipse that fills the given rectangle. * * @param x x coordinate of the top-left corner * @param y y coordinate of the top-left corner * @param w the rectangle width * @param h the rectangle height */ void paintEllipse(const qreal x, const qreal y, const qreal w, const qreal h); /** * Paint the polygon with the points given in points. It automatically closes the polygon * by drawing the line from the last point to the first. */ void paintPolygon(const vQPointF& points); /** Draw a spot at pos using the currently set paint op, brush and color */ void paintAt(const KisPaintInformation &pos, KisDistanceInformation *savedDist); /** * Stroke the given QPainterPath. */ void paintPainterPath(const QPainterPath& path); /** * Fills the area enclosed by the given QPainterPath * Convenience method for fillPainterPath(path, rect) */ void fillPainterPath(const QPainterPath& path); /** * Fills the portion of an area enclosed by the given QPainterPath * - * \param rect the portion of the path to fill + * \param path the portion of the path to fill + * \param requestedRect the rectangle containing the area */ void fillPainterPath(const QPainterPath& path, const QRect &requestedRect); /** * Draw the path using the Pen * * if \p requestedRect is null, the entire path is painted */ void drawPainterPath(const QPainterPath& path, const QPen& pen, const QRect &requestedRect); // convenience overload void drawPainterPath(const QPainterPath& path, const QPen& pen); /** * paint an unstroked one-pixel wide line from specified start position to the * specified end position. * */ void drawLine(const QPointF & start, const QPointF & end); /** * paint an unstroked line with thickness from specified start position to the * specified end position. Scanline algorithm is used. */ void drawLine(const QPointF &start, const QPointF &end, qreal width, bool antialias); /** * paints an unstroked, aliased one-pixel line using the DDA algorithm from specified start position to the * specified end position. * */ void drawDDALine(const QPointF & start, const QPointF & end); /** * Paint an unstroked, wobbly one-pixel wide line from the specified start to the specified * end position. * */ void drawWobblyLine(const QPointF & start, const QPointF & end); /** * Paint an unstroked, anti-aliased one-pixel wide line from the specified start to the specified * end position using the Wu algorithm */ void drawWuLine(const QPointF & start, const QPointF & end); /** * Paint an unstroked wide line from the specified start to the specified - * end position with width varying from @param w1 at the start to @param w2 at + * end position with width varying from @p start at the start to @p end at * the end. * * XXX: the width should be set in doubles, not integers. */ void drawThickLine(const QPointF & start, const QPointF & end, int startWidth, int endWidth); /** * Set the channelflags: a bit array where true means that the * channel corresponding in position with the bit will be read * by the operation, and false means that it will not be affected. * * An empty channelFlags parameter means that all channels are * affected. * - * @param the bit array that masks the source channels; only + * @param channelFlags the bit array that masks the source channels; only * the channels where the corresponding bit is true will will be * composited onto the destination device. */ void setChannelFlags(QBitArray channelFlags); /// @return the channel flags QBitArray channelFlags(); /** - * Set the paintop preset to use. If @param image is given, + * Set the paintop preset to use. If @p image is given, * the paintop will be created using this image as parameter. * Some paintops really want to know about the image they work * for, e.g. the clone paintop. */ void setPaintOpPreset(KisPaintOpPresetSP preset, KisNodeSP node, KisImageSP image); /// Return the paintop preset KisPaintOpPresetSP preset() const; /** * Return the active paintop (which is created based on the specified preset and * will be deleted as soon as the KisPainter instance dies). */ KisPaintOp* paintOp() const; void setMirrorInformation(const QPointF &axesCenter, bool mirrorHorizontally, bool mirrorVertically); void copyMirrorInformationFrom(const KisPainter *other); /** * Returns whether the mirroring methods will do any * work when called */ bool hasMirroring() const; /** * Indicates if horizontal mirroring mode is activated */ bool hasHorizontalMirroring() const; /** * Indicates if vertical mirroring mode is activated */ bool hasVerticalMirroring() const; /** * Mirror \p rc in the requested \p direction around the center point defined * in the painter. */ void mirrorRect(Qt::Orientation direction, QRect *rc) const; /** * Mirror \p dab in the requested direction around the center point defined * in the painter. The dab's offset is adjusted automatically. */ void mirrorDab(Qt::Orientation direction, KisRenderedDab *dab) const; /** * Calculate the list of the mirrored rects that will be painted on the * the canvas when calling renderMirrorMask() at al */ const QVector calculateAllMirroredRects(const QRect &rc); /// Set the current pattern void setPattern(const KoPatternSP pattern); /// Returns the currently set pattern const KoPatternSP pattern() const; /** * Set the color that will be used to paint with, and convert it * to the color space of the current paint device. */ void setPaintColor(const KoColor& color); /// Returns the color that will be used to paint with const KoColor &paintColor() const; /** * Set the current background color, and convert it * to the color space of the current paint device. */ void setBackgroundColor(const KoColor& color); /// Returns the current background color const KoColor &backgroundColor() const; /// Set the current generator (a generator can be used to fill an area void setGenerator(KisFilterConfigurationSP generator); /// @return the current generator configuration const KisFilterConfigurationSP generator() const; /// This enum contains the styles with which we can fill things like polygons and ellipses enum FillStyle { FillStyleNone, FillStyleForegroundColor, FillStyleBackgroundColor, FillStylePattern, FillStyleGradient, FillStyleStrokes, FillStyleGenerator, }; /// Set the current style with which to fill void setFillStyle(FillStyle fillStyle); /// Returns the current fill style FillStyle fillStyle() const; /// Set whether a polygon's filled area should be anti-aliased or not. The default is true. void setAntiAliasPolygonFill(bool antiAliasPolygonFill); /// Return whether a polygon's filled area should be anti-aliased or not bool antiAliasPolygonFill(); /// The style of the brush stroke around polygons and so enum StrokeStyle { StrokeStyleNone, StrokeStyleBrush }; /// Set the current brush stroke style void setStrokeStyle(StrokeStyle strokeStyle); /// Returns the current brush stroke style StrokeStyle strokeStyle() const; void setFlow(quint8 flow); quint8 flow() const; /** * Sets the opacity of the painting and recalculates the * mean opacity of the stroke. This mean value is used to * make ALPHA_DARKEN painting look correct */ void setOpacityUpdateAverage(quint8 opacity); /** * Sets average opacity, that is used to make ALPHA_DARKEN painting look correct */ void setAverageOpacity(qreal averageOpacity); /** * Calculate average opacity value after painting a single dab with \p opacity */ static qreal blendAverageOpacity(qreal opacity, qreal averageOpacity); /// Set the opacity which is used in painting (like filling polygons) void setOpacity(quint8 opacity); /// Returns the opacity that is used in painting quint8 opacity() const; /// Set the composite op for this painter void setCompositeOp(const KoCompositeOp * op); const KoCompositeOp * compositeOp(); /// Set the composite op for this painter by string. /// Note: the colorspace must be set previously! void setCompositeOp(const QString& op); /** * Add \p r to the current set of dirty rects */ void addDirtyRect(const QRect &r); /** * Add \p rects to the current set of dirty rects */ void addDirtyRects(const QVector &rects); /** * Reset the selection to the given selection. All painter actions will be * masked by the specified selection. */ void setSelection(KisSelectionSP selection); /** * @return the selection set on this painter. */ KisSelectionSP selection(); void setGradient(const KoAbstractGradientSP gradient); const KoAbstractGradientSP gradient() const; /** * Set the size of the tile in fillPainterPath, useful when optimizing the use of fillPainterPath * e.g. Spray paintop uses more small tiles, although selections uses bigger tiles. QImage::fill * is quite expensive so with smaller images you can save instructions * Default and maximum size is 256x256 image */ void setMaskImageSize(qint32 width, qint32 height); // /** // * If the alpha channel is locked, the alpha values of the paint device we are painting on // * will not change. // */ // void setLockAlpha(bool protect); // bool alphaLocked() const; /** * set the rendering intent in case pixels need to be converted before painting */ void setRenderingIntent(KoColorConversionTransformation::Intent intent); /** * set the conversion flags in case pixels need to be converted before painting */ void setColorConversionFlags(KoColorConversionTransformation::ConversionFlags conversionFlags); /** * Set interface for running asynchronous jobs by paintops. * * NOTE: the painter does *not* own the interface device. It is the responsibility * of the caller to ensure that the interface object is alive during the lifetime * of the painter. */ void setRunnableStrokeJobsInterface(KisRunnableStrokeJobsInterface *interface); /** * Get the interface for running asynchronous jobs. It is used by paintops mostly. */ KisRunnableStrokeJobsInterface* runnableStrokeJobsInterface() const; protected: /// Initialize, set everything to '0' or defaults void init(); /// Fill the polygon defined by points with the fillStyle void fillPolygon(const vQPointF& points, FillStyle fillStyle); private: KisPainter(const KisPainter&); KisPainter& operator=(const KisPainter&); float frac(float value) { float tmp = 0; return modff(value , &tmp); } float invertFrac(float value) { float tmp = 0; return 1.0f - modff(value , &tmp); } protected: KoUpdater * progressUpdater(); private: template void bitBltImpl(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight); inline void compositeOnePixel(quint8 *dst, const KoColor &color); private: struct Private; Private* const d; }; #endif // KIS_PAINTER_H_ diff --git a/libs/image/kis_raster_keyframe_channel.h b/libs/image/kis_raster_keyframe_channel.h index 2ccec11eec..c2a791f21e 100644 --- a/libs/image/kis_raster_keyframe_channel.h +++ b/libs/image/kis_raster_keyframe_channel.h @@ -1,95 +1,96 @@ /* * Copyright (c) 2015 Jouni Pentikäinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 _KIS_RASTER_KEYFRAME_CHANNEL_H #define _KIS_RASTER_KEYFRAME_CHANNEL_H #include "kis_keyframe_channel.h" class KRITAIMAGE_EXPORT KisRasterKeyframeChannel : public KisKeyframeChannel { Q_OBJECT public: KisRasterKeyframeChannel(const KoID& id, const KisPaintDeviceWSP paintDevice, KisDefaultBoundsBaseSP defaultBounds); KisRasterKeyframeChannel(const KisRasterKeyframeChannel &rhs, KisNode *newParentNode, const KisPaintDeviceWSP newPaintDevice); ~KisRasterKeyframeChannel() override; public: /** * Return the ID of the active frame at a given time. The active frame is * defined by the keyframe at the given time or the last keyframe before it. * @param time * @return active frame id */ int frameIdAt(int time) const; /** * Copy the active frame at given time to target device. * @param keyframe keyframe to copy from * @param targetDevice device to copy the frame to */ void fetchFrame(KisKeyframeSP keyframe, KisPaintDeviceSP targetDevice); /** * Copy the content of the sourceDevice into a new keyframe at given time * @param time position of new keyframe * @param sourceDevice source for content + * @param parentCommand parent command used for stacking */ void importFrame(int time, KisPaintDeviceSP sourceDevice, KUndo2Command *parentCommand); QRect frameExtents(KisKeyframeSP keyframe); QString frameFilename(int frameId) const; /** * When choosing filenames for frames, this will be appended to the node filename */ void setFilenameSuffix(const QString &suffix); bool hasScalarValue() const override; QDomElement toXML(QDomDocument doc, const QString &layerFilename) override; void loadXML(const QDomElement &channelNode) override; void setOnionSkinsEnabled(bool value); bool onionSkinsEnabled() const; protected: KisKeyframeSP createKeyframe(int time, const KisKeyframeSP copySrc, KUndo2Command *parentCommand) override; void destroyKeyframe(KisKeyframeSP key, KUndo2Command *parentCommand) override; void uploadExternalKeyframe(KisKeyframeChannel *srcChannel, int srcTime, KisKeyframeSP dstFrame) override; QRect affectedRect(KisKeyframeSP key) override; void saveKeyframe(KisKeyframeSP keyframe, QDomElement keyframeElement, const QString &layerFilename) override; KisKeyframeSP loadKeyframe(const QDomElement &keyframeNode) override; friend class KisRasterKeyframe; bool keyframeHasContent(const KisKeyframe *keyframe) const; private: void setFrameFilename(int frameId, const QString &filename); QString chooseFrameFilename(int frameId, const QString &layerFilename); int frameId(KisKeyframeSP keyframe) const; int frameId(const KisKeyframe *keyframe) const; struct Private; QScopedPointer m_d; }; #endif diff --git a/libs/image/kis_repeat_iterators_pixel.h b/libs/image/kis_repeat_iterators_pixel.h index 1c0d18bcc3..507e5cb52a 100644 --- a/libs/image/kis_repeat_iterators_pixel.h +++ b/libs/image/kis_repeat_iterators_pixel.h @@ -1,268 +1,288 @@ /* * Copyright (c) 2008 Cyrille Berger * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 _KIS_REPEAT_ITERATORS_PIXEL_H_ #define _KIS_REPEAT_ITERATORS_PIXEL_H_ #include #include "kis_shared.h" #include "tiles3/kis_hline_iterator.h" #include "tiles3/kis_vline_iterator.h" template class KisRepeatHLineIteratorPixelBase; template class KisRepeatVLineIteratorPixelBase; /** * This iterator is an iterator that will "artificially" extend the paint device with the * value of the border when trying to access values outside the range of data. */ template class KisRepeatLineIteratorPixelBase : public KisShared { Q_DISABLE_COPY(KisRepeatLineIteratorPixelBase) public: friend class KisRepeatHLineIteratorPixelBase; friend class KisRepeatVLineIteratorPixelBase; /** - * @param rc indicates the rectangle that truly contains data + * @param dm data manager + * @param x x of top left corner + * @param y y of top left corner + * @param offsetx x offset + * @param offsety y offset + * @param _rc indicates the rectangle that truly contains data + * @param completeListener completion listener */ inline KisRepeatLineIteratorPixelBase(KisDataManager *dm, qint32 x, qint32 y, qint32 offsetx, qint32 offsety, const QRect& _rc, KisIteratorCompleteListener *completeListener); virtual inline ~KisRepeatLineIteratorPixelBase(); public: inline qint32 x() const { return m_realX; } inline qint32 y() const { return m_realY; } inline const quint8 * oldRawData() const { return m_iterator->oldRawData(); } private: KisDataManager* m_dm; qint32 m_realX, m_realY; qint32 m_offsetX, m_offsetY; QRect m_dataRect; T* m_iterator; KisIteratorCompleteListener *m_completeListener; }; /** * This iterator is an iterator that will "artificially" extend the paint device with the * value of the border when trying to access values outside the range of data. */ template class KisRepeatHLineIteratorPixelBase : public KisRepeatLineIteratorPixelBase { public: /** - * @param rc indicates the rectangle that truly contains data + * @param dm data manager + * @param x x of top left corner + * @param y y of top left corner + * @param w width + * @param offsetx x offset + * @param offsety y offset + * @param _rc indicates the rectangle that truly contains data + * @param completeListener completion listener */ inline KisRepeatHLineIteratorPixelBase(KisDataManager *dm, qint32 x, qint32 y, qint32 w, qint32 offsetx, qint32 offsety, const QRect& _rc, KisIteratorCompleteListener *completeListener); inline ~KisRepeatHLineIteratorPixelBase() override; inline bool nextPixel(); /** * Reach next row. */ inline void nextRow(); private: void createIterator(); private: qint32 m_startX; qint32 m_startIteratorX; qint32 m_width; }; /** * This iterator is an iterator that will "artificially" extend the paint device with the * value of the border when trying to access values outside the range of data. */ template class KisRepeatVLineIteratorPixelBase : public KisRepeatLineIteratorPixelBase { public: /** - * @param rc indicates the rectangle that truly contains data + * @param dm data manager + * @param x x of top left corner + * @param y y of top left corner + * @param h height + * @param offsetx x offset + * @param offsety y offset + * @param _rc indicates the rectangle that truly contains data + * @param completeListener completion listener */ inline KisRepeatVLineIteratorPixelBase(KisDataManager *dm, qint32 x, qint32 y, qint32 h, qint32 offsetx, qint32 offsety, const QRect& _rc, KisIteratorCompleteListener *completeListener); inline ~KisRepeatVLineIteratorPixelBase() override; inline KisRepeatVLineIteratorPixelBase & operator ++(); inline bool nextPixel(); /** * Reach next row. */ inline void nextColumn(); private: void createIterator(); private: qint32 m_startY; qint32 m_startIteratorY; qint32 m_height; }; //------------------------ Implementations ------------------------// //---------------- KisRepeatLineIteratorPixelBase -----------------// template KisRepeatLineIteratorPixelBase::KisRepeatLineIteratorPixelBase(KisDataManager *dm, qint32 x, qint32 y, qint32 offsetx, qint32 offsety, const QRect& _rc, KisIteratorCompleteListener *completeListener) : m_dm(dm), m_realX(x), m_realY(y), m_offsetX(offsetx), m_offsetY(offsety), m_dataRect(_rc), m_iterator(0), m_completeListener(completeListener) { } template KisRepeatLineIteratorPixelBase::~KisRepeatLineIteratorPixelBase() { delete m_iterator; } //---------------- KisRepeatHLineIteratorPixelBase ----------------// template KisRepeatHLineIteratorPixelBase::KisRepeatHLineIteratorPixelBase(KisDataManager *dm, qint32 x, qint32 y, qint32 w, qint32 offsetx, qint32 offsety, const QRect& _rc, KisIteratorCompleteListener *completeListener) : KisRepeatLineIteratorPixelBase(dm, x, y, offsetx, offsety , _rc, completeListener), m_startX(x), m_startIteratorX(x), m_width(w) { // Compute the startx value of the iterator if (m_startIteratorX < _rc.left()) { m_startIteratorX = _rc.left(); } createIterator(); } template KisRepeatHLineIteratorPixelBase::~KisRepeatHLineIteratorPixelBase() { } template inline bool KisRepeatHLineIteratorPixelBase::nextPixel() { Q_ASSERT(this->m_iterator); if (this->m_realX >= this->m_dataRect.x() && this->m_realX < this->m_dataRect.x() + this->m_dataRect.width() - 1) { this->m_iterator->nextPixel(); } ++this->m_realX; return (this->m_realX < m_startX + m_width); } template inline void KisRepeatHLineIteratorPixelBase::nextRow() { if (this->m_realY >= this->m_dataRect.y() && this->m_realY < this->m_dataRect.y() + this->m_dataRect.height() - 1) { this->m_iterator->nextRow(); } else { createIterator(); } this->m_realX = this->m_startX; ++this->m_realY; } template void KisRepeatHLineIteratorPixelBase::createIterator() { // Cleanup delete this->m_iterator; qint32 startY = this->m_realY; if (startY < this->m_dataRect.y()) { startY = this->m_dataRect.top(); } if (startY > (this->m_dataRect.y() + this->m_dataRect.height() - 1)) { startY = (this->m_dataRect.y() + this->m_dataRect.height() - 1); } int width = this->m_dataRect.x() + this->m_dataRect.width() - this->m_startIteratorX; this->m_iterator = new T(this->m_dm, this->m_startIteratorX, startY, width, this->m_offsetX, this->m_offsetY, false, this->m_completeListener); this->m_realX = this->m_startX; } //---------------- KisRepeatVLineIteratorPixelBase ----------------// template KisRepeatVLineIteratorPixelBase::KisRepeatVLineIteratorPixelBase(KisDataManager *dm, qint32 x, qint32 y, qint32 h, qint32 offsetx, qint32 offsety, const QRect& _rc, KisIteratorCompleteListener *completeListener) : KisRepeatLineIteratorPixelBase(dm, x, y, offsetx, offsety , _rc, completeListener), m_startY(y), m_startIteratorY(y), m_height(h) { // Compute the startx value of the iterator if (m_startIteratorY < _rc.top()) { m_startIteratorY = _rc.top(); } createIterator(); } template KisRepeatVLineIteratorPixelBase::~KisRepeatVLineIteratorPixelBase() { } template inline bool KisRepeatVLineIteratorPixelBase::nextPixel() { Q_ASSERT(this->m_iterator); if (this->m_realY >= this->m_dataRect.y() && this->m_realY < this->m_dataRect.y() + this->m_dataRect.height() - 1) { this->m_iterator->nextPixel(); } ++this->m_realY; return (this->m_realY < m_startY + m_height); } template inline void KisRepeatVLineIteratorPixelBase::nextColumn() { if (this->m_realX >= this->m_dataRect.x() && this->m_realX < this->m_dataRect.x() + this->m_dataRect.width() - 1) { this->m_iterator->nextColumn(); } else { createIterator(); } this->m_realY = this->m_startY; ++this->m_realX; } template void KisRepeatVLineIteratorPixelBase::createIterator() { // Cleanup delete this->m_iterator; qint32 startX = this->m_realX; if (startX < this->m_dataRect.x()) { startX = this->m_dataRect.x(); } if (startX > (this->m_dataRect.x() + this->m_dataRect.width() - 1)) { startX = (this->m_dataRect.x() + this->m_dataRect.width() - 1); } int height = this->m_dataRect.y() + this->m_dataRect.height() - this->m_startIteratorY; this->m_iterator = new T(this->m_dm, startX, this->m_startIteratorY, height, this->m_offsetX, this->m_offsetY, false, this->m_completeListener); this->m_realY = this->m_startY; } #endif diff --git a/libs/image/kis_selection_based_layer.h b/libs/image/kis_selection_based_layer.h index cc57a75074..08c1ba8304 100644 --- a/libs/image/kis_selection_based_layer.h +++ b/libs/image/kis_selection_based_layer.h @@ -1,210 +1,211 @@ /* * Copyright (c) 2006 Boudewijn Rempt * (c) 2009 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_SELECTION_BASED_LAYER_H_ #define KIS_SELECTION_BASED_LAYER_H_ #include #include "kis_types.h" #include "kis_layer.h" #include "kis_indirect_painting_support.h" #include #include "kis_node_filter_interface.h" class KisFilterConfiguration; /** - * @class KisSelectionBasedLayer describes base behaviour for + * @class KisSelectionBasedLayer + * @brief Describes base behaviour for * selection base classes like KisAdjustmentLayer and KisGeneratorLayer. * These classes should have a persistent selection that controls * the area where filter/generators are applied. The area outside * this selection is not affected by the layer */ class KRITAIMAGE_EXPORT KisSelectionBasedLayer : public KisLayer, public KisIndirectPaintingSupport, public KisNodeFilterInterface { Q_OBJECT public: /** * creates a new layer with the given selection. * Note that the selection will be _copied_ (with COW, though). * @param image the image to set this layer to * @param name name of the layer * @param selection is a mask used by the layer to know * where to apply the filter/generator. */ KisSelectionBasedLayer(KisImageWSP image, const QString &name, KisSelectionSP selection, KisFilterConfigurationSP filterConfig, bool useGeneratorRegistry = false); KisSelectionBasedLayer(const KisSelectionBasedLayer& rhs); ~KisSelectionBasedLayer() override; /** * tells whether the @node can be a child of this layer * @param node to be connected node * @return tells if to be connected is a child of KisMask */ bool allowAsChild(KisNodeSP node) const override; void setImage(KisImageWSP image) override; KisPaintDeviceSP original() const override; KisPaintDeviceSP paintDevice() const override; bool needProjection() const override; /** * resets cached projection of lower layer to a new device * @return void */ virtual void resetCache(); /** * for KisLayer::setDirty(const QRegion&) */ using KisLayer::setDirty; /** * Mark a layer as dirty. We can't use KisLayer's one * as our extent() function doesn't fit for this */ void setDirty() override; public: /** * Returns the selection of the layer * * Do not mix it with selection() which returns * the currently active selection of the image */ KisSelectionSP internalSelection() const; /** * sets the selection of this layer to a copy of * selection * @param selection the selection to set * @return void */ void setInternalSelection(KisSelectionSP selection); /** * When painted in indirect painting mode, the internal selection * might not contain actual selection, because a part of it is * stored on an indirect painting device. This method returns the * merged copy of the real selection. The area in \p rect only is * guaranteed to be prepared. The content of the rest of the * selection is undefined. */ KisSelectionSP fetchComposedInternalSelection(const QRect &rect) const; /** * gets this layer's x coordinate, taking selection into account * @return x-coordinate value */ qint32 x() const override; /** * gets this layer's y coordinate, taking selection into account * @return y-coordinate value */ qint32 y() const override; /** * sets this layer's y coordinate, taking selection into account * @param x x coordinate */ void setX(qint32 x) override; /** * sets this layer's y coordinate, taking selection into account * @param y y coordinate */ void setY(qint32 y) override; public: /** * gets an approximation of where the bounds on actual data * are in this layer, taking selection into account */ QRect extent() const override; /** * returns the exact bounds of where the actual data resides * in this layer, taking selection into account */ QRect exactBounds() const override; /** * copies the image and reformats it to thumbnail size * and returns the new thumbnail image. * @param w width of the thumbnail to create * @param h height of the thumbnail to create * @return the thumbnail image created. */ QImage createThumbnail(qint32 w, qint32 h) override; protected: // override from KisLayer void copyOriginalToProjection(const KisPaintDeviceSP original, KisPaintDeviceSP projection, const QRect& rect) const override; // override from KisNode QRect needRect(const QRect &rect, PositionToFilthy pos = N_FILTHY) const override; protected: void initSelection(); QRect cropChangeRectBySelection(const QRect &rect) const; /** * Sets if the selection should be used in * copyOriginalToProjection() method. * * Default value is 'true'. The descendants should override it to * get desired behaviour. * * Must be called only once in the child's constructor */ void setUseSelectionInProjection(bool value) const; KisKeyframeChannel *requestKeyframeChannel(const QString &id) override; public Q_SLOTS: void slotImageSizeChanged(); /** * gets this layer. Overriddes function in * KisIndirectPaintingSupport * @return this AdjustmentLayer */ KisLayer* layer() { return this; } private: struct Private; Private * const m_d; }; #endif /* KIS_SELECTION_BASED_LAYER_H_ */ diff --git a/libs/image/kis_transform_worker.h b/libs/image/kis_transform_worker.h index 4a9c6db520..df00969cdf 100644 --- a/libs/image/kis_transform_worker.h +++ b/libs/image/kis_transform_worker.h @@ -1,160 +1,160 @@ /* * Copyright (c) 2004 Michael Thaler * Copyright (c) 2005 C. Boemann * Copyright (c) 2010 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_TRANSFORM_WORKER_H_ #define KIS_TRANSFORM_WORKER_H_ #include "kis_types.h" #include "kritaimage_export.h" #include #include class KisPaintDevice; class KisFilterStrategy; class QTransform; class KRITAIMAGE_EXPORT KisTransformWorker { /* What are xshearOrigin, yshearOrigin : * * let's keep it simple and say we only have horizontal shearing (it's similar with vertical shearing) * that means we will apply the transformation : * x' = x + xshear * y and y' = y, where x,y are the old coordinates of the pixels, and x' y' the new coordinates * that means, the more we go down in the image (y++), the more x' is different from x * most of the times, we want to shear a part of the image centered at y = y0 != 0. * i.e. we want x' = x at y = y0 * in that case, it's good to apply instead x' = x + xshear * (y - yshearOrigin), y' = y. * please note that it's still possible to obtain the same result by copying the part you want to shear at * in another paintDevice at y = -y0 and use the transformWorker with yshearOrigin = 0. */ public: KisTransformWorker(KisPaintDeviceSP dev, double xscale, double yscale, double xshear, double yshear, double xshearOrigin, double yshearOrigin, double rotation, qint32 xtranslate, qint32 ytranslate, KoUpdaterPtr progress, KisFilterStrategy *filter); ~KisTransformWorker(); /** * Mirror the specified device along the X or Y axis at the * coordinate \p axis. */ static void mirror(KisPaintDeviceSP dev, qreal axis, Qt::Orientation orientation); /** * Convenience methods for mirror(dev, axis, orientation) */ static void mirrorX(KisPaintDeviceSP dev, qreal axis); static void mirrorY(KisPaintDeviceSP dev, qreal axis); /** * Mirror the device relative to the center of its exactBounds() */ static void mirrorX(KisPaintDeviceSP dev); static void mirrorY(KisPaintDeviceSP dev); /** * Offset the specified device with wrapping around edges of rect specified as QRect(0,0,wrapSize.width, wrapSize.height)* * @param device device to be offset * @param offsetPosition position where the new origin will be - * @param wrapSize width and height of the wrap edge, usual scenario is to use canvas width&height + * @param wrapRect width and height of the wrap edge, usual scenario is to use canvas width&height * **/ static void offset(KisPaintDeviceSP device, const QPoint &offsetPosition, const QRect &wrapRect); public: // returns false if interrupted bool run(); bool runPartial(const QRect &processRect); /** * Returns a matrix of the transformation executed by the worker. * Resulting transformation has the following form (in Qt's matrix * notation (all the matrices are transposed)): * * transform = TS.inverted() * S * TS * SC * R * T * * ,where: * TS - shear origin transpose * S - shear itself (shearX * shearY) * SC - scale - * R - rotation (@rotation parameter) - * T - transpose (@xtranslate, @ytranslate) + * R - rotation (@p rotation parameter) + * T - transpose (@p xtranslate, @p ytranslate) * * WARNING: due to some rounding problems in the worker * the work it does does not correspond to the matrix exactly! * The result always differs 1-3 pixel. So be careful with it * (or fix it) */ QTransform transform() const; /** * Transforms the outline of the pixel selection (if it is valid) */ void transformPixelSelectionOutline(KisPixelSelectionSP pixelSelection) const; private: // XXX (BSAR): Why didn't we use the shared-pointer versions of the paint device classes? // CBR: because the template functions used within don't work if it's not true pointers template void transformPass(KisPaintDevice* src, KisPaintDevice* dst, double xscale, double shear, double dx, KisFilterStrategy *filterStrategy, int portion); friend class KisTransformWorkerTest; static QRect rotateRight90(KisPaintDeviceSP dev, QRect boundRect, KoUpdaterPtr progressUpdater, int portion); static QRect rotateLeft90(KisPaintDeviceSP dev, QRect boundRect, KoUpdaterPtr progressUpdater, int portion); static QRect rotate180(KisPaintDeviceSP dev, QRect boundRect, KoUpdaterPtr progressUpdater, int portion); private: KisPaintDeviceSP m_dev; double m_xscale, m_yscale; double m_xshear, m_yshear, m_rotation; double m_xshearOrigin, m_yshearOrigin; qint32 m_xtranslate, m_ytranslate; KoUpdaterPtr m_progressUpdater; KisFilterStrategy *m_filter; QRect m_boundRect; }; #endif // KIS_TRANSFORM_VISITOR_H_ diff --git a/libs/image/lazybrush/KisWatershedWorker.h b/libs/image/lazybrush/KisWatershedWorker.h index 95fd52c714..aa7c595699 100644 --- a/libs/image/lazybrush/KisWatershedWorker.h +++ b/libs/image/lazybrush/KisWatershedWorker.h @@ -1,82 +1,83 @@ /* * Copyright (c) 2017 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KISWATERSHEDWORKER_H #define KISWATERSHEDWORKER_H #include #include "kis_types.h" #include "kritaimage_export.h" class KoColor; class KRITAIMAGE_EXPORT KisWatershedWorker { public: /** - * Creates an empty watershed worker withouth any strokes attached. The strokes + * Creates an empty watershed worker without any strokes attached. The strokes * should be attached manually with addKeyStroke() call. * * @param heightMap prefiltered height map in alpha8 colorspace, with "0" meaning * background color and "255" meaning line art. Heightmap is *never* * modified by the worker! * @param dst destination device where the result will be written * @param boundingRect the worker refuses to fill outside the bounding rect, considering * that outer area as having +inf height + * @param progress the progress value */ KisWatershedWorker(KisPaintDeviceSP heightMap, KisPaintDeviceSP dst, const QRect &boundingRect, KoUpdater *progress = 0); ~KisWatershedWorker(); /** * @brief Adds a key stroke to the worker. * * The key strokes may intersect, in which case the lastly added stroke will have * a priority over all the previous ones. * * @param dev alpha8 paint device of the key stroke, may contain disjoint areas * @param color the color of the stroke */ void addKeyStroke(KisPaintDeviceSP dev, const KoColor &color); /** * @brief run the filling process using the passes height map, strokes, and write * the result coloring into the destination device * @param cleanUpAmount shows how aggressively we should try to clean up the final * coloring. Should be in range [0.0...1.0] */ void run(qreal cleanUpAmount = 0.0); int testingGroupPositiveEdge(qint32 group, quint8 level); int testingGroupNegativeEdge(qint32 group, quint8 level); int testingGroupForeignEdge(qint32 group, quint8 level); int testingGroupAllyEdge(qint32 group, quint8 level); int testingGroupConflicts(qint32 group, quint8 level, qint32 withGroup); void testingTryRemoveGroup(qint32 group, quint8 level); private: struct Private; const QScopedPointer m_d; }; #endif // KISWATERSHEDWORKER_H diff --git a/libs/image/lazybrush/kis_lazy_fill_tools.h b/libs/image/lazybrush/kis_lazy_fill_tools.h index f8fc15eab9..ad81e3c4a3 100644 --- a/libs/image/lazybrush/kis_lazy_fill_tools.h +++ b/libs/image/lazybrush/kis_lazy_fill_tools.h @@ -1,98 +1,98 @@ /* * Copyright (c) 2016 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 __KIS_LAZY_FILL_TOOLS_H #define __KIS_LAZY_FILL_TOOLS_H #include "kis_types.h" #include "kritaimage_export.h" #include #include class KoColor; namespace KisLazyFillTools { KRITAIMAGE_EXPORT void normalizeAndInvertAlpha8Device(KisPaintDeviceSP dev, const QRect &rect); KRITAIMAGE_EXPORT void normalizeAlpha8Device(KisPaintDeviceSP dev, const QRect &rect); /** * Uses Boykov-Kolmogorov Max-Flow/Min-Cut algorithm to split the - * device \src into two parts. The first part is defined by \p + * device \p src into two parts. The first part is defined by \p * colorScribble and the second part --- by \p * backgroundScribble. In the result of the split the area defined * by \p colorScribble in \p resultDevice is filled with \p * color. Also the same area in \p maskDevice is filled with a * non-null scribble index. * * \p maskDevice is used for limiting the area used for filling * the color. */ KRITAIMAGE_EXPORT void cutOneWay(const KoColor &color, KisPaintDeviceSP src, KisPaintDeviceSP colorScribble, KisPaintDeviceSP backgroundScribble, KisPaintDeviceSP resultDevice, KisPaintDeviceSP maskDevice, const QRect &boundingRect); /** * Returns one pixel from each connected component of \p src. * * WARNING: \p src is used as a temporary device, so it will be * cleared(!) after the execution of the algorithm */ KRITAIMAGE_EXPORT QVector splitIntoConnectedComponents(KisPaintDeviceSP src, const QRect &boundingRect); struct KRITAIMAGE_EXPORT KeyStroke : public boost::equality_comparable { KeyStroke(); KeyStroke(KisPaintDeviceSP _dev, const KoColor &_color, bool isTransparent = false); friend bool operator==(const KeyStroke& t1, const KeyStroke&t2); KisPaintDeviceSP dev; KoColor color; bool isTransparent; }; struct KRITAIMAGE_EXPORT FilteringOptions : public boost::equality_comparable { FilteringOptions() = default; FilteringOptions(bool _useEdgeDetection, qreal _edgeDetectionSize, qreal _fuzzyRadius, qreal _cleanUpAmount); friend bool operator==(const FilteringOptions &t1, const FilteringOptions &t2); // default values for filtering: disabled bool useEdgeDetection = false; qreal edgeDetectionSize = 4; qreal fuzzyRadius = 0; qreal cleanUpAmount = 0.0; }; }; #endif /* __KIS_LAZY_FILL_TOOLS_H */ diff --git a/libs/image/lazybrush/patched_boykov_kolmogorov_max_flow.hpp b/libs/image/lazybrush/patched_boykov_kolmogorov_max_flow.hpp index c9cf90a076..b2a13e70de 100644 --- a/libs/image/lazybrush/patched_boykov_kolmogorov_max_flow.hpp +++ b/libs/image/lazybrush/patched_boykov_kolmogorov_max_flow.hpp @@ -1,882 +1,882 @@ // Copyright (c) 2006, Stephan Diederich // // This code may be used under either of the following two licences: // // 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, sublicense, 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 OR COPYRIGHT // HOLDERS 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. OF SUCH DAMAGE. // // Or: // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_BOYKOV_KOLMOGOROV_MAX_FLOW_HPP #define BOOST_BOYKOV_KOLMOGOROV_MAX_FLOW_HPP #include #include #include #include #include #include #include // for std::min and std::max #include #include #include #include #include #include #include #include // The algorithm impelemented here is described in: // // Boykov, Y., Kolmogorov, V. "An Experimental Comparison of Min-Cut/Max-Flow // Algorithms for Energy Minimization in Vision", In IEEE Transactions on // Pattern Analysis and Machine Intelligence, vol. 26, no. 9, pp. 1124-1137, // Sep 2004. // // For further reading, also see: // // Kolmogorov, V. "Graph Based Algorithms for Scene Reconstruction from Two or // More Views". PhD thesis, Cornell University, Sep 2003. namespace boost { namespace detail { template class bk_max_flow { typedef typename property_traits::value_type tEdgeVal; typedef graph_traits tGraphTraits; typedef typename tGraphTraits::vertex_iterator vertex_iterator; typedef typename tGraphTraits::vertex_descriptor vertex_descriptor; typedef typename tGraphTraits::edge_descriptor edge_descriptor; typedef typename tGraphTraits::edge_iterator edge_iterator; typedef typename tGraphTraits::out_edge_iterator out_edge_iterator; typedef boost::queue tQueue; //queue of vertices, used in adoption-stage typedef typename property_traits::value_type tColorValue; typedef color_traits tColorTraits; typedef typename property_traits::value_type tDistanceVal; public: bk_max_flow(Graph& g, EdgeCapacityMap cap, ResidualCapacityEdgeMap res, ReverseEdgeMap rev, PredecessorMap pre, ColorMap color, DistanceMap dist, IndexMap idx, vertex_descriptor src, vertex_descriptor sink): m_g(g), m_index_map(idx), m_cap_map(cap), m_res_cap_map(res), m_rev_edge_map(rev), m_pre_map(pre), m_tree_map(color), m_dist_map(dist), m_source(src), m_sink(sink), m_active_nodes(), m_in_active_list_vec(num_vertices(g), false), m_in_active_list_map(make_iterator_property_map(m_in_active_list_vec.begin(), m_index_map)), m_has_parent_vec(num_vertices(g), false), m_has_parent_map(make_iterator_property_map(m_has_parent_vec.begin(), m_index_map)), m_time_vec(num_vertices(g), 0), m_time_map(make_iterator_property_map(m_time_vec.begin(), m_index_map)), m_flow(0), m_time(1), m_last_grow_vertex(graph_traits::null_vertex()){ // initialize the color-map with gray-values vertex_iterator vi, v_end; for(boost::tie(vi, v_end) = vertices(m_g); vi != v_end; ++vi){ set_tree(*vi, tColorTraits::gray()); } // Initialize flow to zero which means initializing // the residual capacity equal to the capacity edge_iterator ei, e_end; for(boost::tie(ei, e_end) = edges(m_g); ei != e_end; ++ei) { put(m_res_cap_map, *ei, get(m_cap_map, *ei)); BOOST_ASSERT(get(m_rev_edge_map, get(m_rev_edge_map, *ei)) == *ei); //check if the reverse edge map is build up properly } //init the search trees with the two terminals set_tree(m_source, tColorTraits::black()); set_tree(m_sink, tColorTraits::white()); put(m_time_map, m_source, 1); put(m_time_map, m_sink, 1); } tEdgeVal max_flow(){ //augment direct paths from SOURCE->SINK and SOURCE->VERTEX->SINK augment_direct_paths(); //start the main-loop while(true){ bool path_found; edge_descriptor connecting_edge; boost::tie(connecting_edge, path_found) = grow(); //find a path from source to sink if(!path_found){ //we're finished, no more paths were found break; } ++m_time; augment(connecting_edge); //augment that path adopt(); //rebuild search tree structure } return m_flow; } // the complete class is protected, as we want access to members in // derived test-class (see test/boykov_kolmogorov_max_flow_test.cpp) protected: void augment_direct_paths(){ // in a first step, we augment all direct paths from source->NODE->sink // and additionally paths from source->sink. This improves especially // graphcuts for segmentation, as most of the nodes have source/sink // connects but shouldn't have an impact on other maxflow problems // (this is done in grow() anyway) out_edge_iterator ei, e_end; for(boost::tie(ei, e_end) = out_edges(m_source, m_g); ei != e_end; ++ei){ edge_descriptor from_source = *ei; vertex_descriptor current_node = target(from_source, m_g); if(current_node == m_sink){ tEdgeVal cap = get(m_res_cap_map, from_source); put(m_res_cap_map, from_source, 0); m_flow += cap; continue; } edge_descriptor to_sink; bool is_there; boost::tie(to_sink, is_there) = lookup_edge(current_node, m_sink, m_g); if(is_there){ tEdgeVal cap_from_source = get(m_res_cap_map, from_source); tEdgeVal cap_to_sink = get(m_res_cap_map, to_sink); if(cap_from_source > cap_to_sink){ set_tree(current_node, tColorTraits::black()); add_active_node(current_node); set_edge_to_parent(current_node, from_source); put(m_dist_map, current_node, 1); put(m_time_map, current_node, 1); // add stuff to flow and update residuals. we don't need to // update reverse_edges, as incoming/outgoing edges to/from // source/sink don't count for max-flow put(m_res_cap_map, from_source, get(m_res_cap_map, from_source) - cap_to_sink); put(m_res_cap_map, to_sink, 0); m_flow += cap_to_sink; } else if(cap_to_sink > 0){ set_tree(current_node, tColorTraits::white()); add_active_node(current_node); set_edge_to_parent(current_node, to_sink); put(m_dist_map, current_node, 1); put(m_time_map, current_node, 1); // add stuff to flow and update residuals. we don't need to update // reverse_edges, as incoming/outgoing edges to/from source/sink // don't count for max-flow put(m_res_cap_map, to_sink, get(m_res_cap_map, to_sink) - cap_from_source); put(m_res_cap_map, from_source, 0); m_flow += cap_from_source; } } else if(get(m_res_cap_map, from_source)){ // there is no sink connect, so we can't augment this path, but to // avoid adding m_source to the active nodes, we just activate this // node and set the appropriate things set_tree(current_node, tColorTraits::black()); set_edge_to_parent(current_node, from_source); put(m_dist_map, current_node, 1); put(m_time_map, current_node, 1); add_active_node(current_node); } } for(boost::tie(ei, e_end) = out_edges(m_sink, m_g); ei != e_end; ++ei){ edge_descriptor to_sink = get(m_rev_edge_map, *ei); vertex_descriptor current_node = source(to_sink, m_g); if(get(m_res_cap_map, to_sink)){ set_tree(current_node, tColorTraits::white()); set_edge_to_parent(current_node, to_sink); put(m_dist_map, current_node, 1); put(m_time_map, current_node, 1); add_active_node(current_node); } } } /** * Returns a pair of an edge and a boolean. if the bool is true, the * edge is a connection of a found path from s->t , read "the link" and * source(returnVal, m_g) is the end of the path found in the source-tree * target(returnVal, m_g) is the beginning of the path found in the sink-tree */ std::pair grow(){ BOOST_ASSERT(m_orphans.empty()); vertex_descriptor current_node; while((current_node = get_next_active_node()) != graph_traits::null_vertex()){ //if there is one BOOST_ASSERT(get_tree(current_node) != tColorTraits::gray() && (has_parent(current_node) || current_node == m_source || current_node == m_sink)); if(get_tree(current_node) == tColorTraits::black()){ //source tree growing out_edge_iterator ei, e_end; if(current_node != m_last_grow_vertex){ m_last_grow_vertex = current_node; boost::tie(m_last_grow_edge_it, m_last_grow_edge_end) = out_edges(current_node, m_g); } for(; m_last_grow_edge_it != m_last_grow_edge_end; ++m_last_grow_edge_it) { edge_descriptor out_edge = *m_last_grow_edge_it; if(get(m_res_cap_map, out_edge) > 0){ //check if we have capacity left on this edge vertex_descriptor other_node = target(out_edge, m_g); if(get_tree(other_node) == tColorTraits::gray()){ //it's a free node set_tree(other_node, tColorTraits::black()); //acquire other node to our search tree set_edge_to_parent(other_node, out_edge); //set us as parent put(m_dist_map, other_node, get(m_dist_map, current_node) + 1); //and update the distance-heuristic put(m_time_map, other_node, get(m_time_map, current_node)); add_active_node(other_node); } else if(get_tree(other_node) == tColorTraits::black()) { // we do this to get shorter paths. check if we are nearer to // the source as its parent is if(is_closer_to_terminal(current_node, other_node)){ set_edge_to_parent(other_node, out_edge); put(m_dist_map, other_node, get(m_dist_map, current_node) + 1); put(m_time_map, other_node, get(m_time_map, current_node)); } } else{ BOOST_ASSERT(get_tree(other_node)==tColorTraits::white()); //kewl, found a path from one to the other search tree, return // the connecting edge in src->sink dir return std::make_pair(out_edge, true); } } } //for all out-edges } //source-tree-growing else{ BOOST_ASSERT(get_tree(current_node) == tColorTraits::white()); out_edge_iterator ei, e_end; if(current_node != m_last_grow_vertex){ m_last_grow_vertex = current_node; boost::tie(m_last_grow_edge_it, m_last_grow_edge_end) = out_edges(current_node, m_g); } for(; m_last_grow_edge_it != m_last_grow_edge_end; ++m_last_grow_edge_it){ edge_descriptor in_edge = get(m_rev_edge_map, *m_last_grow_edge_it); if(get(m_res_cap_map, in_edge) > 0){ //check if there is capacity left vertex_descriptor other_node = source(in_edge, m_g); if(get_tree(other_node) == tColorTraits::gray()){ //it's a free node set_tree(other_node, tColorTraits::white()); //acquire that node to our search tree set_edge_to_parent(other_node, in_edge); //set us as parent add_active_node(other_node); //activate that node put(m_dist_map, other_node, get(m_dist_map, current_node) + 1); //set its distance put(m_time_map, other_node, get(m_time_map, current_node));//and time } else if(get_tree(other_node) == tColorTraits::white()){ if(is_closer_to_terminal(current_node, other_node)){ //we are closer to the sink than its parent is, so we "adopt" him set_edge_to_parent(other_node, in_edge); put(m_dist_map, other_node, get(m_dist_map, current_node) + 1); put(m_time_map, other_node, get(m_time_map, current_node)); } } else{ BOOST_ASSERT(get_tree(other_node)==tColorTraits::black()); //kewl, found a path from one to the other search tree, // return the connecting edge in src->sink dir return std::make_pair(in_edge, true); } } } //for all out-edges } //sink-tree growing //all edges of that node are processed, and no more paths were found. // remove if from the front of the active queue finish_node(current_node); } //while active_nodes not empty //no active nodes anymore and no path found, we're done return std::make_pair(edge_descriptor(), false); } /** * augments path from s->t and updates residual graph * source(e, m_g) is the end of the path found in the source-tree * target(e, m_g) is the beginning of the path found in the sink-tree * this phase generates orphans on satured edges, if the attached verts are * from different search-trees orphans are ordered in distance to * sink/source. first the farest from the source are front_inserted into * the orphans list, and after that the sink-tree-orphans are * front_inserted. when going to adoption stage the orphans are popped_front, * and so we process the nearest verts to the terminals first */ void augment(edge_descriptor e) { BOOST_ASSERT(get_tree(target(e, m_g)) == tColorTraits::white()); BOOST_ASSERT(get_tree(source(e, m_g)) == tColorTraits::black()); BOOST_ASSERT(m_orphans.empty()); const tEdgeVal bottleneck = find_bottleneck(e); //now we push the found flow through the path //for each edge we saturate we have to look for the verts that belong to that edge, one of them becomes an orphans //now process the connecting edge put(m_res_cap_map, e, get(m_res_cap_map, e) - bottleneck); BOOST_ASSERT(get(m_res_cap_map, e) >= 0); put(m_res_cap_map, get(m_rev_edge_map, e), get(m_res_cap_map, get(m_rev_edge_map, e)) + bottleneck); //now we follow the path back to the source vertex_descriptor current_node = source(e, m_g); while(current_node != m_source){ edge_descriptor pred = get_edge_to_parent(current_node); const tEdgeVal new_pred_cap = get(m_res_cap_map, pred) - bottleneck; put(m_res_cap_map, pred, new_pred_cap); BOOST_ASSERT(get(m_res_cap_map, pred) >= 0); const edge_descriptor pred_rev = get(m_rev_edge_map, pred); put(m_res_cap_map, pred_rev, get(m_res_cap_map, pred_rev) + bottleneck); if(new_pred_cap == 0){ set_no_parent(current_node); m_orphans.push_front(current_node); } current_node = source(pred, m_g); } //then go forward in the sink-tree current_node = target(e, m_g); while(current_node != m_sink){ edge_descriptor pred = get_edge_to_parent(current_node); const tEdgeVal new_pred_cap = get(m_res_cap_map, pred) - bottleneck; put(m_res_cap_map, pred, new_pred_cap); BOOST_ASSERT(get(m_res_cap_map, pred) >= 0); const edge_descriptor pred_rev = get(m_rev_edge_map, pred); put(m_res_cap_map, pred_rev, get(m_res_cap_map, pred_rev) + bottleneck); if(new_pred_cap == 0){ set_no_parent(current_node); m_orphans.push_front(current_node); } current_node = target(pred, m_g); } //and add it to the max-flow m_flow += bottleneck; } /** * returns the bottleneck of a s->t path (end_of_path is last vertex in * source-tree, begin_of_path is first vertex in sink-tree) */ inline tEdgeVal find_bottleneck(edge_descriptor e){ BOOST_USING_STD_MIN(); tEdgeVal minimum_cap = get(m_res_cap_map, e); vertex_descriptor current_node = source(e, m_g); //first go back in the source tree while(current_node != m_source){ edge_descriptor pred = get_edge_to_parent(current_node); minimum_cap = min BOOST_PREVENT_MACRO_SUBSTITUTION(minimum_cap, get(m_res_cap_map, pred)); current_node = source(pred, m_g); } //then go forward in the sink-tree current_node = target(e, m_g); while(current_node != m_sink){ edge_descriptor pred = get_edge_to_parent(current_node); minimum_cap = min BOOST_PREVENT_MACRO_SUBSTITUTION(minimum_cap, get(m_res_cap_map, pred)); current_node = target(pred, m_g); } return minimum_cap; } /** * rebuild search trees * empty the queue of orphans, and find new parents for them or just drop * them from the search trees */ void adopt(){ while(!m_orphans.empty() || !m_child_orphans.empty()){ vertex_descriptor current_node; if(m_child_orphans.empty()){ //get the next orphan from the main-queue and remove it current_node = m_orphans.front(); m_orphans.pop_front(); } else{ current_node = m_child_orphans.front(); m_child_orphans.pop(); } if(get_tree(current_node) == tColorTraits::black()){ //we're in the source-tree tDistanceVal min_distance = (std::numeric_limits::max)(); edge_descriptor new_parent_edge; out_edge_iterator ei, e_end; for(boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){ const edge_descriptor in_edge = get(m_rev_edge_map, *ei); BOOST_ASSERT(target(in_edge, m_g) == current_node); //we should be the target of this edge if(get(m_res_cap_map, in_edge) > 0){ vertex_descriptor other_node = source(in_edge, m_g); if(get_tree(other_node) == tColorTraits::black() && has_source_connect(other_node)){ if(get(m_dist_map, other_node) < min_distance){ min_distance = get(m_dist_map, other_node); new_parent_edge = in_edge; } } } } if(min_distance != (std::numeric_limits::max)()){ set_edge_to_parent(current_node, new_parent_edge); put(m_dist_map, current_node, min_distance + 1); put(m_time_map, current_node, m_time); } else{ put(m_time_map, current_node, 0); for(boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){ edge_descriptor in_edge = get(m_rev_edge_map, *ei); vertex_descriptor other_node = source(in_edge, m_g); if(get_tree(other_node) == tColorTraits::black() && other_node != m_source){ if(get(m_res_cap_map, in_edge) > 0){ add_active_node(other_node); } if(has_parent(other_node) && source(get_edge_to_parent(other_node), m_g) == current_node){ //we are the parent of that node //it has to find a new parent, too set_no_parent(other_node); m_child_orphans.push(other_node); } } } set_tree(current_node, tColorTraits::gray()); } //no parent found } //source-tree-adoption else{ //now we should be in the sink-tree, check that... BOOST_ASSERT(get_tree(current_node) == tColorTraits::white()); out_edge_iterator ei, e_end; edge_descriptor new_parent_edge; tDistanceVal min_distance = (std::numeric_limits::max)(); for(boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){ const edge_descriptor out_edge = *ei; if(get(m_res_cap_map, out_edge) > 0){ const vertex_descriptor other_node = target(out_edge, m_g); if(get_tree(other_node) == tColorTraits::white() && has_sink_connect(other_node)) if(get(m_dist_map, other_node) < min_distance){ min_distance = get(m_dist_map, other_node); new_parent_edge = out_edge; } } } if(min_distance != (std::numeric_limits::max)()){ set_edge_to_parent(current_node, new_parent_edge); put(m_dist_map, current_node, min_distance + 1); put(m_time_map, current_node, m_time); } else{ put(m_time_map, current_node, 0); for(boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){ const edge_descriptor out_edge = *ei; const vertex_descriptor other_node = target(out_edge, m_g); if(get_tree(other_node) == tColorTraits::white() && other_node != m_sink){ if(get(m_res_cap_map, out_edge) > 0){ add_active_node(other_node); } if(has_parent(other_node) && target(get_edge_to_parent(other_node), m_g) == current_node){ //we were it's parent, so it has to find a new one, too set_no_parent(other_node); m_child_orphans.push(other_node); } } } set_tree(current_node, tColorTraits::gray()); } //no parent found } //sink-tree adoption } //while !orphans.empty() } //adopt /** * return next active vertex if there is one, otherwise a null_vertex */ inline vertex_descriptor get_next_active_node(){ while(true){ if(m_active_nodes.empty()) return graph_traits::null_vertex(); vertex_descriptor v = m_active_nodes.front(); //if it has no parent, this node can't be active (if its not source or sink) if(!has_parent(v) && v != m_source && v != m_sink){ m_active_nodes.pop(); put(m_in_active_list_map, v, false); } else{ BOOST_ASSERT(get_tree(v) == tColorTraits::black() || get_tree(v) == tColorTraits::white()); return v; } } } /** * adds v as an active vertex, but only if its not in the list already */ inline void add_active_node(vertex_descriptor v){ BOOST_ASSERT(get_tree(v) != tColorTraits::gray()); if(get(m_in_active_list_map, v)){ if (m_last_grow_vertex == v) { m_last_grow_vertex = graph_traits::null_vertex(); } return; } else{ put(m_in_active_list_map, v, true); m_active_nodes.push(v); } } /** * finish_node removes a node from the front of the active queue (its called in grow phase, if no more paths can be found using this node) */ inline void finish_node(vertex_descriptor v){ BOOST_ASSERT(m_active_nodes.front() == v); m_active_nodes.pop(); put(m_in_active_list_map, v, false); m_last_grow_vertex = graph_traits::null_vertex(); } /** * removes a vertex from the queue of active nodes (actually this does nothing, * but checks if this node has no parent edge, as this is the criteria for * being no more active) */ inline void remove_active_node(vertex_descriptor v){ (void)v; // disable unused parameter warning BOOST_ASSERT(!has_parent(v)); } /** * returns the search tree of v; tColorValue::black() for source tree, * white() for sink tree, gray() for no tree */ inline tColorValue get_tree(vertex_descriptor v) const { return get(m_tree_map, v); } /** * sets search tree of v; tColorValue::black() for source tree, white() * for sink tree, gray() for no tree */ inline void set_tree(vertex_descriptor v, tColorValue t){ put(m_tree_map, v, t); } /** * returns edge to parent vertex of v; */ inline edge_descriptor get_edge_to_parent(vertex_descriptor v) const{ return get(m_pre_map, v); } /** * returns true if the edge stored in m_pre_map[v] is a valid entry */ inline bool has_parent(vertex_descriptor v) const{ return get(m_has_parent_map, v); } /** * sets edge to parent vertex of v; */ inline void set_edge_to_parent(vertex_descriptor v, edge_descriptor f_edge_to_parent){ BOOST_ASSERT(get(m_res_cap_map, f_edge_to_parent) > 0); put(m_pre_map, v, f_edge_to_parent); put(m_has_parent_map, v, true); } /** * removes the edge to parent of v (this is done by invalidating the * entry an additional map) */ inline void set_no_parent(vertex_descriptor v){ put(m_has_parent_map, v, false); } /** - * checks if vertex v has a connect to the sink-vertex (@var m_sink) + * checks if vertex v has a connect to the sink-vertex (@p m_sink) * @param v the vertex which is checked * @return true if a path to the sink was found, false if not */ inline bool has_sink_connect(vertex_descriptor v){ tDistanceVal current_distance = 0; vertex_descriptor current_vertex = v; while(true){ if(get(m_time_map, current_vertex) == m_time){ //we found a node which was already checked this round. use it for distance calculations current_distance += get(m_dist_map, current_vertex); break; } if(current_vertex == m_sink){ put(m_time_map, m_sink, m_time); break; } if(has_parent(current_vertex)){ //it has a parent, so get it current_vertex = target(get_edge_to_parent(current_vertex), m_g); ++current_distance; } else{ //no path found return false; } } current_vertex=v; while(get(m_time_map, current_vertex) != m_time){ put(m_dist_map, current_vertex, current_distance); --current_distance; put(m_time_map, current_vertex, m_time); current_vertex = target(get_edge_to_parent(current_vertex), m_g); } return true; } /** - * checks if vertex v has a connect to the source-vertex (@var m_source) + * checks if vertex v has a connect to the source-vertex (@p m_source) * @param v the vertex which is checked * @return true if a path to the source was found, false if not */ inline bool has_source_connect(vertex_descriptor v){ tDistanceVal current_distance = 0; vertex_descriptor current_vertex = v; while(true){ if(get(m_time_map, current_vertex) == m_time){ //we found a node which was already checked this round. use it for distance calculations current_distance += get(m_dist_map, current_vertex); break; } if(current_vertex == m_source){ put(m_time_map, m_source, m_time); break; } if(has_parent(current_vertex)){ //it has a parent, so get it current_vertex = source(get_edge_to_parent(current_vertex), m_g); ++current_distance; } else{ //no path found return false; } } current_vertex=v; while(get(m_time_map, current_vertex) != m_time){ put(m_dist_map, current_vertex, current_distance); --current_distance; put(m_time_map, current_vertex, m_time); current_vertex = source(get_edge_to_parent(current_vertex), m_g); } return true; } /** * returns true, if p is closer to a terminal than q */ inline bool is_closer_to_terminal(vertex_descriptor p, vertex_descriptor q){ //checks the timestamps first, to build no cycles, and after that the real distance return (get(m_time_map, q) <= get(m_time_map, p) && get(m_dist_map, q) > get(m_dist_map, p)+1); } //////// // member vars //////// Graph& m_g; IndexMap m_index_map; EdgeCapacityMap m_cap_map; ResidualCapacityEdgeMap m_res_cap_map; ReverseEdgeMap m_rev_edge_map; PredecessorMap m_pre_map; //stores paths found in the growth stage ColorMap m_tree_map; //maps each vertex into one of the two search tree or none (gray()) DistanceMap m_dist_map; //stores distance to source/sink nodes vertex_descriptor m_source; vertex_descriptor m_sink; tQueue m_active_nodes; std::vector m_in_active_list_vec; iterator_property_map::iterator, IndexMap> m_in_active_list_map; std::list m_orphans; tQueue m_child_orphans; // we use a second queuqe for child orphans, as they are FIFO processed std::vector m_has_parent_vec; iterator_property_map::iterator, IndexMap> m_has_parent_map; std::vector m_time_vec; //timestamp of each node, used for sink/source-path calculations iterator_property_map::iterator, IndexMap> m_time_map; tEdgeVal m_flow; long m_time; vertex_descriptor m_last_grow_vertex; out_edge_iterator m_last_grow_edge_it; out_edge_iterator m_last_grow_edge_end; }; } //namespace boost::detail /** * non-named-parameter version, given everything * this is the catch all version */ template typename property_traits::value_type boykov_kolmogorov_max_flow(Graph& g, CapacityEdgeMap cap, ResidualCapacityEdgeMap res_cap, ReverseEdgeMap rev_map, PredecessorMap pre_map, ColorMap color, DistanceMap dist, IndexMap idx, typename graph_traits::vertex_descriptor src, typename graph_traits::vertex_descriptor sink) { typedef typename graph_traits::vertex_descriptor vertex_descriptor; typedef typename graph_traits::edge_descriptor edge_descriptor; //as this method is the last one before we instantiate the solver, we do the concept checks here BOOST_CONCEPT_ASSERT(( VertexListGraphConcept )); //to have vertices(), num_vertices(), BOOST_CONCEPT_ASSERT(( EdgeListGraphConcept )); //to have edges() BOOST_CONCEPT_ASSERT(( IncidenceGraphConcept )); //to have source(), target() and out_edges() BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept )); //read flow-values from edges BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept )); //write flow-values to residuals BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept )); //read out reverse edges BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept )); //store predecessor there BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept )); //write corresponding tree BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept )); //write distance to source/sink BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept )); //get index 0...|V|-1 BOOST_ASSERT(num_vertices(g) >= 2 && src != sink); detail::bk_max_flow< Graph, CapacityEdgeMap, ResidualCapacityEdgeMap, ReverseEdgeMap, PredecessorMap, ColorMap, DistanceMap, IndexMap > algo(g, cap, res_cap, rev_map, pre_map, color, dist, idx, src, sink); return algo.max_flow(); } /** * non-named-parameter version, given capacity, residucal_capacity, * reverse_edges, and an index map. */ template typename property_traits::value_type boykov_kolmogorov_max_flow(Graph& g, CapacityEdgeMap cap, ResidualCapacityEdgeMap res_cap, ReverseEdgeMap rev, IndexMap idx, typename graph_traits::vertex_descriptor src, typename graph_traits::vertex_descriptor sink) { typename graph_traits::vertices_size_type n_verts = num_vertices(g); std::vector::edge_descriptor> predecessor_vec(n_verts); std::vector color_vec(n_verts); std::vector::vertices_size_type> distance_vec(n_verts); return boykov_kolmogorov_max_flow( g, cap, res_cap, rev, make_iterator_property_map(predecessor_vec.begin(), idx), make_iterator_property_map(color_vec.begin(), idx), make_iterator_property_map(distance_vec.begin(), idx), idx, src, sink); } /** * non-named-parameter version, some given: capacity, residual_capacity, * reverse_edges, color_map and an index map. Use this if you are interested in * the minimum cut, as the color map provides that info. */ template typename property_traits::value_type boykov_kolmogorov_max_flow(Graph& g, CapacityEdgeMap cap, ResidualCapacityEdgeMap res_cap, ReverseEdgeMap rev, ColorMap color, IndexMap idx, typename graph_traits::vertex_descriptor src, typename graph_traits::vertex_descriptor sink) { typename graph_traits::vertices_size_type n_verts = num_vertices(g); std::vector::edge_descriptor> predecessor_vec(n_verts); std::vector::vertices_size_type> distance_vec(n_verts); return boykov_kolmogorov_max_flow( g, cap, res_cap, rev, make_iterator_property_map(predecessor_vec.begin(), idx), color, make_iterator_property_map(distance_vec.begin(), idx), idx, src, sink); } /** * named-parameter version, some given */ template typename property_traits::const_type>::value_type boykov_kolmogorov_max_flow(Graph& g, typename graph_traits::vertex_descriptor src, typename graph_traits::vertex_descriptor sink, const bgl_named_params& params) { return boykov_kolmogorov_max_flow( g, choose_const_pmap(get_param(params, edge_capacity), g, edge_capacity), choose_pmap(get_param(params, edge_residual_capacity), g, edge_residual_capacity), choose_const_pmap(get_param(params, edge_reverse), g, edge_reverse), choose_pmap(get_param(params, vertex_predecessor), g, vertex_predecessor), choose_pmap(get_param(params, vertex_color), g, vertex_color), choose_pmap(get_param(params, vertex_distance), g, vertex_distance), choose_const_pmap(get_param(params, vertex_index), g, vertex_index), src, sink); } /** * named-parameter version, none given */ template typename property_traits::const_type>::value_type boykov_kolmogorov_max_flow(Graph& g, typename graph_traits::vertex_descriptor src, typename graph_traits::vertex_descriptor sink) { bgl_named_params params(0); // bogus empty param return boykov_kolmogorov_max_flow(g, src, sink, params); } } // namespace boost #endif // BOOST_BOYKOV_KOLMOGOROV_MAX_FLOW_HPP diff --git a/libs/image/tiles3/kis_tiled_data_manager.h b/libs/image/tiles3/kis_tiled_data_manager.h index b6f8384d17..0ddb815456 100644 --- a/libs/image/tiles3/kis_tiled_data_manager.h +++ b/libs/image/tiles3/kis_tiled_data_manager.h @@ -1,420 +1,430 @@ /* * Copyright (c) 2004 Boudewijn Rempt * (c) 2009 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_TILEDDATAMANAGER_H_ #define KIS_TILEDDATAMANAGER_H_ #include #include #include #include #include #include "config-hash-table-implementaion.h" //#include "kis_debug.h" #include "kritaimage_export.h" #ifdef USE_LOCK_FREE_HASH_TABLE #include "kis_tile_hash_table2.h" #else #include "kis_tile_hash_table.h" #endif // USE_LOCK_FREE_HASH_TABLE #include "kis_memento_manager.h" #include "kis_memento.h" #include "KisTiledExtentManager.h" class KisTiledDataManager; typedef KisSharedPtr KisTiledDataManagerSP; class KisTiledIterator; class KisTiledRandomAccessor; class KisPaintDeviceWriter; class QIODevice; /** * KisTiledDataManager implements the interface that KisDataManager defines * * The interface definition is enforced by KisDataManager calling all the methods * which must also be defined in KisTiledDataManager. It is not allowed to change the interface * as other datamangers may also rely on the same interface. * * * Storing undo/redo data * * Offering ordered and unordered iterators over rects of pixels * * (eventually) efficiently loading and saving data in a format * that may allow deferred loading. * * A datamanager knows nothing about the type of pixel data except * how many quint8's a single pixel takes. */ class KRITAIMAGE_EXPORT KisTiledDataManager : public KisShared { private: static const qint32 LEGACY_VERSION = 1; static const qint32 CURRENT_VERSION = 2; protected: /*FIXME:*/ public: KisTiledDataManager(quint32 pixelSize, const quint8 *defPixel); virtual ~KisTiledDataManager(); KisTiledDataManager(const KisTiledDataManager &dm); KisTiledDataManager & operator=(const KisTiledDataManager &dm); protected: // Allow the baseclass of iterators access to the interior // derived iterator classes must go through KisTiledIterator friend class KisTiledIterator; friend class KisBaseIterator; friend class KisTiledRandomAccessor; friend class KisRandomAccessor2; friend class KisStressJob; public: void setDefaultPixel(const quint8 *defPixel); const quint8 *defaultPixel() const { return m_defaultPixel; } /** * Every iterator fetches both types of tiles all the time: old and new. * For projection devices these tiles are **always** the same, but doing * two distinct calls makes double pressure on the read-write lock in the * hash table. * * Merging two calls into one allows us to avoid additional tile fetch from * the hash table and therefore reduce waiting time. */ inline void getTilesPair(qint32 col, qint32 row, bool writable, KisTileSP *tile, KisTileSP *oldTile) { *tile = getTile(col, row, writable); bool unused; *oldTile = m_mementoManager->getCommitedTile(col, row, unused); if (!*oldTile) { *oldTile = *tile; } } inline KisTileSP getTile(qint32 col, qint32 row, bool writable) { if (writable) { bool newTile; KisTileSP tile = m_hashTable->getTileLazy(col, row, newTile); if (newTile) { m_extentManager.notifyTileAdded(col, row); } return tile; } else { bool unused; return m_hashTable->getReadOnlyTileLazy(col, row, unused); } } inline KisTileSP getReadOnlyTileLazy(qint32 col, qint32 row, bool &existingTile) { return m_hashTable->getReadOnlyTileLazy(col, row, existingTile); } inline KisTileSP getOldTile(qint32 col, qint32 row, bool &existingTile) { KisTileSP tile = m_mementoManager->getCommitedTile(col, row, existingTile); return tile ? tile : getReadOnlyTileLazy(col, row, existingTile); } inline KisTileSP getOldTile(qint32 col, qint32 row) { bool unused; return getOldTile(col, row, unused); } KisMementoSP getMemento() { QWriteLocker locker(&m_lock); KisMementoSP memento = m_mementoManager->getMemento(); memento->saveOldDefaultPixel(m_defaultPixel, m_pixelSize); return memento; } /** * Finishes having already started transaction */ void commit() { QWriteLocker locker(&m_lock); KisMementoSP memento = m_mementoManager->currentMemento(); if(memento) { memento->saveNewDefaultPixel(m_defaultPixel, m_pixelSize); } m_mementoManager->commit(); } void rollback(KisMementoSP memento) { commit(); QWriteLocker locker(&m_lock); m_mementoManager->rollback(m_hashTable); const quint8 *defaultPixel = memento->oldDefaultPixel(); if(memcmp(m_defaultPixel, defaultPixel, m_pixelSize)) { setDefaultPixelImpl(defaultPixel); } recalculateExtent(); } void rollforward(KisMementoSP memento) { commit(); QWriteLocker locker(&m_lock); m_mementoManager->rollforward(m_hashTable); const quint8 *defaultPixel = memento->newDefaultPixel(); if(memcmp(m_defaultPixel, defaultPixel, m_pixelSize)) { setDefaultPixelImpl(defaultPixel); } recalculateExtent(); } bool hasCurrentMemento() const { return m_mementoManager->hasCurrentMemento(); //return true; } /** * Removes all the history that preceds the revision * pointed by oldestMemento. That is after calling to * purgeHistory(someMemento) you won't be able to do * rollback(someMemento) anymore. */ void purgeHistory(KisMementoSP oldestMemento) { QWriteLocker locker(&m_lock); m_mementoManager->purgeHistory(oldestMemento); } static void releaseInternalPools(); protected: /** * Reads and writes the tiles */ bool write(KisPaintDeviceWriter &store); bool read(QIODevice *stream); void purge(const QRect& area); inline quint32 pixelSize() const { return m_pixelSize; } /* FIXME:*/ public: void extent(qint32 &x, qint32 &y, qint32 &w, qint32 &h) const; void setExtent(qint32 x, qint32 y, qint32 w, qint32 h); QRect extent() const; void setExtent(QRect newRect); QRegion region() const; void clear(QRect clearRect, quint8 clearValue); void clear(QRect clearRect, const quint8 *clearPixel); void clear(qint32 x, qint32 y, qint32 w, qint32 h, quint8 clearValue); void clear(qint32 x, qint32 y, qint32 w, qint32 h, const quint8 *clearPixel); void clear(); /** * Clones rect from another datamanager. The cloned area will be * shared between both datamanagers as much as possible using * copy-on-write. Parts of the rect that cannot be shared * (cross tiles) are deep-copied, */ void bitBlt(KisTiledDataManager *srcDM, const QRect &rect); /** * The same as \ref bitBlt(), but reads old data */ void bitBltOldData(KisTiledDataManager *srcDM, const QRect &rect); /** * Clones rect from another datamanager in a rough and fast way. * All the tiles touched by rect will be shared, between both * managers, that means it will copy a bigger area than was * requested. This method is supposed to be used for bitBlt'ing * into temporary paint devices. */ void bitBltRough(KisTiledDataManager *srcDM, const QRect &rect); /** * The same as \ref bitBltRough(), but reads old data */ void bitBltRoughOldData(KisTiledDataManager *srcDM, const QRect &rect); /** * write the specified data to x, y. There is no checking on pixelSize! */ void setPixel(qint32 x, qint32 y, const quint8 * data); /** * Copy the bytes in the specified rect to a vector. The caller is responsible * for managing the vector. * + * \param bytes the bytes + * \param x x of top left corner + * \param y y of top left corner + * \param w width + * \param h height * \param dataRowStride is the step (in bytes) which should be * added to \p bytes pointer to get to the * next row */ void readBytes(quint8 * bytes, qint32 x, qint32 y, qint32 w, qint32 h, qint32 dataRowStride = -1) const; /** * Copy the bytes in the vector to the specified rect. If there are bytes left * in the vector after filling the rect, they will be ignored. If there are * not enough bytes, the rest of the rect will be filled with the default value * given (by default, 0); * + * \param bytes the bytes + * \param x x of top left corner + * \param y y of top left corner + * \param w width + * \param h height * \param dataRowStride is the step (in bytes) which should be * added to \p bytes pointer to get to the * next row */ void writeBytes(const quint8 * bytes, qint32 x, qint32 y, qint32 w, qint32 h, qint32 dataRowStride = -1); /** * Copy the bytes in the paint device into a vector of arrays of bytes, * where the number of arrays is the number of channels in the * paint device. If the specified area is larger than the paint * device's extent, the default pixel will be read. */ QVector readPlanarBytes(QVector channelsizes, qint32 x, qint32 y, qint32 w, qint32 h) const; /** * Write the data in the separate arrays to the channels. If there * are less vectors than channels, the remaining channels will not * be copied. If any of the arrays points to 0, the channel in * that location will not be touched. If the specified area is * larger than the paint device, the paint device will be * extended. There are no guards: if the area covers more pixels * than there are bytes in the arrays, krita will happily fill * your paint device with areas of memory you never wanted to be * read. Krita may also crash. */ void writePlanarBytes(QVector planes, QVector channelsizes, qint32 x, qint32 y, qint32 w, qint32 h); /** * Get the number of contiguous columns starting at x, valid for all values * of y between minY and maxY. */ qint32 numContiguousColumns(qint32 x, qint32 minY, qint32 maxY) const; /** * Get the number of contiguous rows starting at y, valid for all values * of x between minX and maxX. */ qint32 numContiguousRows(qint32 y, qint32 minX, qint32 maxX) const; /** * Get the row stride at pixel (x, y). This is the number of bytes to add to a * pointer to pixel (x, y) to access (x, y + 1). */ qint32 rowStride(qint32 x, qint32 y) const; private: KisTileHashTable *m_hashTable; KisMementoManager *m_mementoManager; quint8* m_defaultPixel; qint32 m_pixelSize; KisTiledExtentManager m_extentManager; mutable QReadWriteLock m_lock; private: // Allow compression routines to calculate (col,row) coordinates // and pixel size friend class KisAbstractTileCompressor; friend class KisTileDataWrapper; qint32 xToCol(qint32 x) const; qint32 yToRow(qint32 y) const; private: void setDefaultPixelImpl(const quint8 *defPixel); bool writeTilesHeader(KisPaintDeviceWriter &store, quint32 numTiles); bool processTilesHeader(QIODevice *stream, quint32 &numTiles); qint32 divideRoundDown(qint32 x, const qint32 y) const; void recalculateExtent(); quint8* duplicatePixel(qint32 num, const quint8 *pixel); template void bitBltImpl(KisTiledDataManager *srcDM, const QRect &rect); template void bitBltRoughImpl(KisTiledDataManager *srcDM, const QRect &rect); void writeBytesBody(const quint8 *data, qint32 x, qint32 y, qint32 width, qint32 height, qint32 dataRowStride = -1); void readBytesBody(quint8 *data, qint32 x, qint32 y, qint32 width, qint32 height, qint32 dataRowStride = -1) const; template void writePlanarBytesBody(QVector planes, QVector channelsizes, qint32 x, qint32 y, qint32 w, qint32 h); QVector readPlanarBytesBody(QVector channelsizes, qint32 x, qint32 y, qint32 w, qint32 h) const; public: void debugPrintInfo() { m_mementoManager->debugPrintInfo(); } }; inline qint32 KisTiledDataManager::divideRoundDown(qint32 x, const qint32 y) const { /** * Equivalent to the following: * -(( -x + (y-1) ) / y) */ return x >= 0 ? x / y : -(((-x - 1) / y) + 1); } inline qint32 KisTiledDataManager::xToCol(qint32 x) const { return divideRoundDown(x, KisTileData::WIDTH); } inline qint32 KisTiledDataManager::yToRow(qint32 y) const { return divideRoundDown(y, KisTileData::HEIGHT); } // during development the following line helps to check the interface is correct // it should be safe to keep it here even during normal compilation //#include "kis_datamanager.h" #endif // KIS_TILEDDATAMANAGER_H_ diff --git a/libs/image/tiles3/swap/kis_abstract_compression.h b/libs/image/tiles3/swap/kis_abstract_compression.h index 31e7ca0a73..c34eb7ed37 100644 --- a/libs/image/tiles3/swap/kis_abstract_compression.h +++ b/libs/image/tiles3/swap/kis_abstract_compression.h @@ -1,88 +1,94 @@ /* * Copyright (c) 2010 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 __KIS_ABSTRACT_COMPRESSION_H #define __KIS_ABSTRACT_COMPRESSION_H #include "kritaimage_export.h" #include /** * Base class for compression operations */ class KRITAIMAGE_EXPORT KisAbstractCompression { public: KisAbstractCompression(); virtual ~KisAbstractCompression(); /** - * Compresses \a input buffer into \a output buffer. + * Compresses \p input buffer into \p output buffer. * WARNING: Be careful, output buffer must be at least * outputBufferSize(inputLength) size! + * \param input the input + * \param inputLength the input length + * \param output the output * \param outputLength is not used! * \return number of bytes written to the output buffer * and 0 if error occurred. * * \see outputBufferSize() */ virtual qint32 compress(const quint8* input, qint32 inputLength, quint8* output, qint32 outputLength) = 0; /** - * Decompresses \a input buffer into \a output buffer. + * Decompresses \p input buffer into \p output buffer. * WARNING: output buffer must be able to fit the input data + * \param input the input + * \param inputLength the input length + * \param output the output * \param outputLength is not used! * \return number of bytes written to the output buffer * and 0 if error occurred. */ virtual qint32 decompress(const quint8* input, qint32 inputLength, quint8* output, qint32 outputLength) = 0; /** * Returns minimal allowed size of output buffer for compression */ virtual qint32 outputBufferSize(qint32 dataSize) = 0; /** * Some algorithms may decide to optimize them work depending on * the usual size of the data. * Default implementation of KisAbstractCompression class does nothing. */ virtual void adjustForDataSize(qint32 dataSize); public: /** * Additional interface for jumbling color channels order */ /** * e.g. RGBARGBARGBA -> RRRGGGBBBAAA * NOTE: performs mixing of bytes, not channels! */ static void linearizeColors(quint8 *input, quint8 *output, qint32 dataSize, qint32 pixelSize); /** * e.g. RRRGGGBBBAAA -> RGBARGBARGBA * NOTE: performs mixing of bytes, not channels! */ static void delinearizeColors(quint8 *input, quint8 *output, qint32 dataSize, qint32 pixelSize); }; #endif /* __KIS_ABSTRACT_COMPRESSION_H */ diff --git a/libs/image/tiles3/swap/kis_abstract_tile_compressor.h b/libs/image/tiles3/swap/kis_abstract_tile_compressor.h index d5cbdfb6cd..1acd1eb847 100644 --- a/libs/image/tiles3/swap/kis_abstract_tile_compressor.h +++ b/libs/image/tiles3/swap/kis_abstract_tile_compressor.h @@ -1,103 +1,108 @@ /* * Copyright (c) 2010 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 __KIS_ABSTRACT_TILE_COMPRESSOR_H #define __KIS_ABSTRACT_TILE_COMPRESSOR_H #include "kritaimage_export.h" #include "../kis_tile.h" #include "../kis_tiled_data_manager.h" class KisPaintDeviceWriter; /** * Base class for compressing a tile and wrapping it with a header */ class KisAbstractTileCompressor; typedef KisSharedPtr KisAbstractTileCompressorSP; class KRITAIMAGE_EXPORT KisAbstractTileCompressor : public KisShared { public: KisAbstractTileCompressor(); virtual ~KisAbstractTileCompressor(); public: /** * Compresses the \a tile and writes it into the \a stream. * Used by datamanager in load/save routines * * \see compressTile() */ virtual bool writeTile(KisTileSP tile, KisPaintDeviceWriter &store) = 0; /** * Decompresses the \a tile from the \a stream. * Used by datamanager in load/save routines * * \see decompressTile() */ virtual bool readTile(QIODevice *stream, KisTiledDataManager *dm) = 0; /** - * Compresses a \a tileData and writes it into the \a buffer. + * Compresses a \p tileData and writes it into the \p buffer. * The buffer must be at least tileDataBufferSize() bytes long. * Actual number of bytes written is returned using out-parameter - * \a bytesWritten + * \p bytesWritten * * \param tileData an existing tile data. It should be created * and acquired by the caller. + * \param buffer the buffer + * \param bufferSize the size of the buffer + * \param bytesWritten the number of written bytes * * \see tileDataBufferSize() */ virtual void compressTileData(KisTileData *tileData,quint8 *buffer, qint32 bufferSize, qint32 &bytesWritten) = 0; /** - * Decompresses a \a tileData from a given \a buffer. + * Decompresses a \p tileData from a given \p buffer. * - * \param tileData an existing tile data wrere the result + * \param buffer the buffer + * \param bufferSize the size of the buffer + * \param tileData an existing tile data where the result * will be written to. It should be created and acquired * by the caller. * */ virtual bool decompressTileData(quint8 *buffer, qint32 bufferSize, KisTileData *tileData) = 0; /** * Return the number of bytes needed for compressing one tile */ virtual qint32 tileDataBufferSize(KisTileData *tileData) = 0; protected: inline qint32 xToCol(KisTiledDataManager *dm, qint32 x) { return dm->xToCol(x); } inline qint32 yToRow(KisTiledDataManager *dm, qint32 y) { return dm->yToRow(y); } inline qint32 pixelSize(KisTiledDataManager *dm) { return dm->pixelSize(); } }; #endif /* __KIS_ABSTRACT_TILE_COMPRESSOR_H */ diff --git a/libs/image/tiles3/swap/kis_memory_window.h b/libs/image/tiles3/swap/kis_memory_window.h index 8e4fa29190..4f54a4e3bb 100644 --- a/libs/image/tiles3/swap/kis_memory_window.h +++ b/libs/image/tiles3/swap/kis_memory_window.h @@ -1,82 +1,83 @@ /* * Copyright (c) 2010 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 __KIS_MEMORY_WINDOW_H #define __KIS_MEMORY_WINDOW_H #include #include "kis_chunk_allocator.h" #define DEFAULT_WINDOW_SIZE (16*MiB) class KRITAIMAGE_EXPORT KisMemoryWindow { public: /** - * @param swapDir. If the dir doesn't exist, it'll be created, if it's empty QDir::tempPath will be used. + * @param swapDir If the dir doesn't exist, it'll be created, if it's empty QDir::tempPath will be used. + * @param writeWindowSize write window size. */ KisMemoryWindow(const QString &swapDir, quint64 writeWindowSize = DEFAULT_WINDOW_SIZE); ~KisMemoryWindow(); inline quint8* getReadChunkPtr(KisChunk readChunk) { return getReadChunkPtr(readChunk.data()); } inline quint8* getWriteChunkPtr(KisChunk writeChunk) { return getWriteChunkPtr(writeChunk.data()); } quint8* getReadChunkPtr(const KisChunkData &readChunk); quint8* getWriteChunkPtr(const KisChunkData &writeChunk); private: struct MappingWindow { MappingWindow(quint64 _defaultSize) : chunk(0,0), window(0), defaultSize(_defaultSize) { } quint8* calculatePointer(const KisChunkData &other) const { return window + other.m_begin - chunk.m_begin; } KisChunkData chunk; quint8 *window; const quint64 defaultSize; }; private: bool adjustWindow(const KisChunkData &requestedChunk, MappingWindow *adjustingWindow, MappingWindow *otherWindow); private: QTemporaryFile m_file; bool m_valid; MappingWindow m_readWindowEx; MappingWindow m_writeWindowEx; }; #endif /* __KIS_MEMORY_WINDOW_H */ diff --git a/libs/libkis/Canvas.h b/libs/libkis/Canvas.h index e6329e2ab1..e143e6366d 100644 --- a/libs/libkis/Canvas.h +++ b/libs/libkis/Canvas.h @@ -1,126 +1,126 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 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 Lesser 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 LIBKIS_CANVAS_H #define LIBKIS_CANVAS_H #include #include "kritalibkis_export.h" #include "libkis.h" class KoCanvasBase; class KisDisplayColorConverter; /** * Canvas wraps the canvas inside a view on an image/document. * It is responsible for the view parameters of the document: * zoom, rotation, mirror, wraparound and instant preview. */ class KRITALIBKIS_EXPORT Canvas : public QObject { Q_OBJECT public: explicit Canvas(KoCanvasBase *canvas, QObject *parent = 0); ~Canvas() override; bool operator==(const Canvas &other) const; bool operator!=(const Canvas &other) const; public Q_SLOTS: /** * @return the current zoomlevel. 1.0 is 100%. */ qreal zoomLevel() const; /** - * @brief setZoomLevel set the zoomlevel to the given @param value. 1.0 is 100%. + * @brief setZoomLevel set the zoomlevel to the given @p value. 1.0 is 100%. */ void setZoomLevel(qreal value); /** * @brief resetZoom set the zoomlevel to 100% */ void resetZoom(); /** * @return the rotation of the canvas in degrees. */ qreal rotation() const; /** * @brief setRotation set the rotation of the canvas to the given @param angle in degrees. */ void setRotation(qreal angle); /** * @brief resetRotation reset the canvas rotation. */ void resetRotation(); /** * @return return true if the canvas is mirrored, false otherwise. */ bool mirror() const; /** * @brief setMirror turn the canvas mirroring on or off depending on @param value */ void setMirror(bool value); /** * @return true if the canvas is in wraparound mode, false if not. Only when OpenGL is enabled, * is wraparound mode available. */ bool wrapAroundMode() const; /** * @brief setWrapAroundMode set wraparound mode to @param enable */ void setWrapAroundMode(bool enable); /** * @return true if the canvas is in Instant Preview mode, false if not. Only when OpenGL is enabled, * is Instant Preview mode available. */ bool levelOfDetailMode() const; /** * @brief setLevelOfDetailMode sets Instant Preview to @param enable */ void setLevelOfDetailMode(bool enable); /** * @return the view that holds this canvas */ View *view() const; private: friend class ManagedColor; KisDisplayColorConverter *displayColorConverter() const; struct Private; Private *const d; }; #endif // LIBKIS_CANVAS_H diff --git a/libs/libkis/CloneLayer.h b/libs/libkis/CloneLayer.h index 7d523a8cbe..177be530ca 100644 --- a/libs/libkis/CloneLayer.h +++ b/libs/libkis/CloneLayer.h @@ -1,65 +1,65 @@ /* * Copyright (c) 2017 Wolthera van Hövell tot Westerflier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 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 Lesser 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 LIBKIS_CLONELAYER_H #define LIBKIS_CLONELAYER_H #include #include "Node.h" #include #include "kritalibkis_export.h" #include "libkis.h" /** * @brief The CloneLayer class * A clone layer is a layer that takes a reference inside the image * and shows the exact same pixeldata. * * If the original is updated, the clone layer will update too. */ class KRITALIBKIS_EXPORT CloneLayer : public Node { Q_OBJECT Q_DISABLE_COPY(CloneLayer) public: explicit CloneLayer(KisImageSP image, QString name, KisLayerSP source, QObject *parent = 0); /** * @brief CloneLayer * function for wrapping a preexisting node into a clonelayer object. - * @param clone - * @param parent + * @param layer the clone layer + * @param parent the parent QObject */ explicit CloneLayer(KisCloneLayerSP layer, QObject *parent = 0); ~CloneLayer() override; public Q_SLOTS: /** * @brief type Krita has several types of nodes, split in layers and masks. Group * layers can contain other layers, any layer can contain masks. * * @return clonelayer */ virtual QString type() const override; }; #endif // LIBKIS_PAINTLAYER_H diff --git a/libs/libkis/Document.h b/libs/libkis/Document.h index 4d6abccbc1..49352fe25c 100644 --- a/libs/libkis/Document.h +++ b/libs/libkis/Document.h @@ -1,851 +1,855 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 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 Lesser 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 LIBKIS_DOCUMENT_H #define LIBKIS_DOCUMENT_H #include #include "kritalibkis_export.h" #include "libkis.h" #include "GroupLayer.h" #include "CloneLayer.h" #include "FileLayer.h" #include "FilterLayer.h" #include "FillLayer.h" #include "VectorLayer.h" #include "FilterMask.h" #include "SelectionMask.h" class KisDocument; /** * The Document class encapsulates a Krita Document/Image. A Krita document is an Image with * a filename. Libkis does not differentiate between a document and an image, like Krita does * internally. */ class KRITALIBKIS_EXPORT Document : public QObject { Q_OBJECT Q_DISABLE_COPY(Document) public: explicit Document(KisDocument *document, QObject *parent = 0); ~Document() override; bool operator==(const Document &other) const; bool operator!=(const Document &other) const; /** * @brief horizontalGuides * The horizontal guides. * @return a list of the horizontal positions of guides. */ QList horizontalGuides() const; /** * @brief verticalGuides * The vertical guide lines. * @return a list of vertical guides. */ QList verticalGuides() const; /** * @brief guidesVisible * Returns guide visibility. * @return whether the guides are visible. */ bool guidesVisible() const; /** * @brief guidesLocked * Returns guide lockedness. * @return whether the guides are locked. */ bool guidesLocked() const; public Q_SLOTS: /** * @brief clone create a shallow clone of this document. * @return a new Document that should be identical to this one in every respect. */ Document *clone() const; /** * Batchmode means that no actions on the document should show dialogs or popups. * @return true if the document is in batchmode. */ bool batchmode() const; /** - * Set batchmode to @param value. If batchmode is true, then there should be no popups + * Set batchmode to @p value. If batchmode is true, then there should be no popups * or dialogs shown to the user. */ void setBatchmode(bool value); /** * @brief activeNode retrieve the node that is currently active in the currently active window * @return the active node. If there is no active window, the first child node is returned. */ Node* activeNode() const; /** * @brief setActiveNode make the given node active in the currently active view and window * @param value the node to make active. */ void setActiveNode(Node* value); /** * @brief toplevelNodes return a list with all top level nodes in the image graph */ QList topLevelNodes() const; /** * @brief nodeByName searches the node tree for a node with the given name and returns it * @param name the name of the node * @return the first node with the given name or 0 if no node is found */ Node *nodeByName(const QString &name) const; /** * colorDepth A string describing the color depth of the image: *
    *
  • U8: unsigned 8 bits integer, the most common type
  • *
  • U16: unsigned 16 bits integer
  • *
  • F16: half, 16 bits floating point. Only available if Krita was built with OpenEXR
  • *
  • F32: 32 bits floating point
  • *
* @return the color depth. */ QString colorDepth() const; /** * @brief colorModel retrieve the current color model of this document: *
    *
  • A: Alpha mask
  • *
  • RGBA: RGB with alpha channel (The actual order of channels is most often BGR!)
  • *
  • XYZA: XYZ with alpha channel
  • *
  • LABA: LAB with alpha channel
  • *
  • CMYKA: CMYK with alpha channel
  • *
  • GRAYA: Gray with alpha channel
  • *
  • YCbCrA: YCbCr with alpha channel
  • *
* @return the internal color model string. */ QString colorModel() const; /** * @return the name of the current color profile */ QString colorProfile() const; /** * @brief setColorProfile set the color profile of the image to the given profile. The profile has to * be registered with krita and be compatible with the current color model and depth; the image data * is not converted. * @param colorProfile * @return false if the colorProfile name does not correspond to to a registered profile or if assigning * the profile failed. */ bool setColorProfile(const QString &colorProfile); /** * @brief setColorSpace convert the nodes and the image to the given colorspace. The conversion is * done with Perceptual as intent, High Quality and No LCMS Optimizations as flags and no blackpoint * compensation. * * @param colorModel A string describing the color model of the image: *
    *
  • A: Alpha mask
  • *
  • RGBA: RGB with alpha channel (The actual order of channels is most often BGR!)
  • *
  • XYZA: XYZ with alpha channel
  • *
  • LABA: LAB with alpha channel
  • *
  • CMYKA: CMYK with alpha channel
  • *
  • GRAYA: Gray with alpha channel
  • *
  • YCbCrA: YCbCr with alpha channel
  • *
* @param colorDepth A string describing the color depth of the image: *
    *
  • U8: unsigned 8 bits integer, the most common type
  • *
  • U16: unsigned 16 bits integer
  • *
  • F16: half, 16 bits floating point. Only available if Krita was built with OpenEXR
  • *
  • F32: 32 bits floating point
  • *
* @param colorProfile a valid color profile for this color model and color depth combination. * @return false the combination of these arguments does not correspond to a colorspace. */ bool setColorSpace(const QString &colorModel, const QString &colorDepth, const QString &colorProfile); /** * @brief backgroundColor returns the current background color of the document. The color will * also include the opacity. * * @return QColor */ QColor backgroundColor(); /** * @brief setBackgroundColor sets the background color of the document. It will trigger a projection * update. * * @param color A QColor. The color will be converted from sRGB. * @return bool */ bool setBackgroundColor(const QColor &color); /** * @brief documentInfo creates and XML document representing document and author information. * @return a string containing a valid XML document with the right information about the document * and author. The DTD can be found here: * * https://phabricator.kde.org/source/krita/browse/master/krita/dtd/ * * @code * * * * * My Document * * * * * Unknown * 1 * 35 * 2017-02-27T20:15:09 * 2017-02-27T20:14:33 * * * * Boudewijn Rempt * * * * * * * * * * * * * * * @endcode * */ QString documentInfo() const; /** * @brief setDocumentInfo set the Document information to the information contained in document * @param document A string containing a valid XML document that conforms to the document-info DTD * that can be found here: * * https://phabricator.kde.org/source/krita/browse/master/krita/dtd/ */ void setDocumentInfo(const QString &document); /** * @return the full path to the document, if it has been set. */ QString fileName() const; /** * @brief setFileName set the full path of the document to @param value */ void setFileName(QString value); /** * @return the height of the image in pixels */ int height() const; /** * @brief setHeight resize the document to @param value height. This is a canvas resize, not a scale. */ void setHeight(int value); /** - * @return the name of the document. This is the title field in the @see documentInfo + * @return the name of the document. This is the title field in the @ref documentInfo */ QString name() const; /** - * @brief setName sets the name of the document to @param value. This is the title field in the @see documentInfo + * @brief setName sets the name of the document to @p value. This is the title field in the @ref documentInfo */ void setName(QString value); /** * @return the resolution in pixels per inch */ int resolution() const; /** * @brief setResolution set the resolution of the image; this does not scale the image * @param value the resolution in pixels per inch */ void setResolution(int value); /** * @brief rootNode the root node is the invisible group layer that contains the entire node * hierarchy. * @return the root of the image */ Node* rootNode() const; /** * @brief selection Create a Selection object around the global selection, if there is one. * @return the global selection or None if there is no global selection. */ Selection* selection() const; /** * @brief setSelection set or replace the global selection * @param value a valid selection object. */ void setSelection(Selection* value); /** * @return the width of the image in pixels. */ int width() const; /** * @brief setWidth resize the document to @param value width. This is a canvas resize, not a scale. */ void setWidth(int value); /** * @return the left edge of the canvas in pixels. */ int xOffset() const; /** - * @brief setXOffset sets the left edge of the canvas to @param x. + * @brief setXOffset sets the left edge of the canvas to @p x. */ void setXOffset(int x); /** * @return the top edge of the canvas in pixels. */ int yOffset() const; /** - * @brief setYOffset sets the top edge of the canvas to @param y. + * @brief setYOffset sets the top edge of the canvas to @p y. */ void setYOffset(int y); /** * @return xRes the horizontal resolution of the image in pixels per pt (there are 72 pts to an inch) */ double xRes() const; /** * @brief setXRes set the horizontal resolution of the image to xRes in pixels per pt. (there are 72 pts to an inch) */ void setXRes(double xRes) const; /** * @return yRes the vertical resolution of the image in pixels per pt (there are 72 pts to an inch) */ double yRes() const; /** * @brief setYRes set the vertical resolution of the image to yRes in pixels per pt. (there are 72 pts to an inch) */ void setYRes(double yRes) const; /** * @brief pixelData reads the given rectangle from the image projection and returns it as a byte * array. The pixel data starts top-left, and is ordered row-first. * * The byte array can be interpreted as follows: 8 bits images have one byte per channel, * and as many bytes as there are channels. 16 bits integer images have two bytes per channel, * representing an unsigned short. 16 bits float images have two bytes per channel, representing * a half, or 16 bits float. 32 bits float images have four bytes per channel, representing a * float. * * You can read outside the image boundaries; those pixels will be transparent black. * * The order of channels is: * *
    *
  • Integer RGBA: Blue, Green, Red, Alpha *
  • Float RGBA: Red, Green, Blue, Alpha *
  • LabA: L, a, b, Alpha *
  • CMYKA: Cyan, Magenta, Yellow, Key, Alpha *
  • XYZA: X, Y, Z, A *
  • YCbCrA: Y, Cb, Cr, Alpha *
* * The byte array is a copy of the original image data. In Python, you can use bytes, bytearray * and the struct module to interpret the data and construct, for instance, a Pillow Image object. * * @param x x position from where to start reading * @param y y position from where to start reading * @param w row length to read * @param h number of rows to read * @return a QByteArray with the pixel data. The byte array may be empty. */ QByteArray pixelData(int x, int y, int w, int h) const; /** * @brief close Close the document: remove it from Krita's internal list of documents and * close all views. If the document is modified, you should save it first. There will be * no prompt for saving. * * After closing the document it becomes invalid. * * @return true if the document is closed. */ bool close(); /** - * @brief crop the image to rectangle described by @param x, @param y, - * @param w and @param h + * @brief crop the image to rectangle described by @p x, @p y, + * @p w and @p h + * @param x x coordinate of the top left corner + * @param y y coordinate of the top left corner + * @param w width + * @param h height */ void crop(int x, int y, int w, int h); /** * @brief exportImage export the image, without changing its URL to the given path. * @param filename the full path to which the image is to be saved * @param exportConfiguration a configuration object appropriate to the file format. * An InfoObject will used to that configuration. * * The supported formats have specific configurations that must be used when in * batchmode. They are described below: * *\b png *
    *
  • alpha: bool (True or False) *
  • compression: int (1 to 9) *
  • forceSRGB: bool (True or False) *
  • indexed: bool (True or False) *
  • interlaced: bool (True or False) *
  • saveSRGBProfile: bool (True or False) *
  • transparencyFillcolor: rgb (Ex:[255,255,255]) *
* *\b jpeg *
    *
  • baseline: bool (True or False) *
  • exif: bool (True or False) *
  • filters: bool (['ToolInfo', 'Anonymizer']) *
  • forceSRGB: bool (True or False) *
  • iptc: bool (True or False) *
  • is_sRGB: bool (True or False) *
  • optimize: bool (True or False) *
  • progressive: bool (True or False) *
  • quality: int (0 to 100) *
  • saveProfile: bool (True or False) *
  • smoothing: int (0 to 100) *
  • subsampling: int (0 to 3) *
  • transparencyFillcolor: rgb (Ex:[255,255,255]) *
  • xmp: bool (True or False) *
* @return true if the export succeeded, false if it failed. */ bool exportImage(const QString &filename, const InfoObject &exportConfiguration); /** * @brief flatten all layers in the image */ void flatten(); /** * @brief resizeImage resizes the canvas to the given left edge, top edge, width and height. * Note: This doesn't scale, use scale image for that. * @param x the new left edge * @param y the new top edge * @param w the new width * @param h the new height */ void resizeImage(int x, int y, int w, int h); /** * @brief scaleImage * @param w the new width * @param h the new height * @param xres the new xres * @param yres the new yres * @param strategy the scaling strategy. There's several ones amongst these that aren't available in the regular UI. * The list of filters is extensible and can be retrieved with Krita::filter *
    *
  • Hermite
  • *
  • Bicubic - Adds pixels using the color of surrounding pixels. Produces smoother tonal gradations than Bilinear.
  • *
  • Box - Replicate pixels in the image. Preserves all the original detail, but can produce jagged effects.
  • *
  • Bilinear - Adds pixels averaging the color values of surrounding pixels. Produces medium quality results when the image is scaled from half to two times the original size.
  • *
  • Bell
  • *
  • BSpline
  • *
  • Kanczos3 - Offers similar results than Bicubic, but maybe a little bit sharper. Can produce light and dark halos along strong edges.
  • *
  • Mitchell
  • *
*/ void scaleImage(int w, int h, int xres, int yres, QString strategy); /** * @brief rotateImage * Rotate the image by the given radians. * @param radians the amount you wish to rotate the image in radians */ void rotateImage(double radians); /** * @brief shearImage shear the whole image. * @param angleX the X-angle in degrees to shear by * @param angleY the Y-angle in degrees to shear by */ void shearImage(double angleX, double angleY); /** * @brief save the image to its currently set path. The modified flag of the * document will be reset * @return true if saving succeeded, false otherwise. */ bool save(); /** - * @brief saveAs save the document under the @param filename. The document's - * filename will be reset to @param filename. + * @brief saveAs save the document under the @p filename. The document's + * filename will be reset to @p filename. * @param filename the new filename (full path) for the document * @return true if saving succeeded, false otherwise. */ bool saveAs(const QString &filename); /** * @brief createNode create a new node of the given type. The node is not added * to the node hierarchy; you need to do that by finding the right parent node, * getting its list of child nodes and adding the node in the right place, then * calling Node::SetChildNodes * * @param name The name of the node * * @param nodeType The type of the node. Valid types are: *
    *
  • paintlayer *
  • grouplayer *
  • filelayer *
  • filterlayer *
  • filllayer *
  • clonelayer *
  • vectorlayer *
  • transparencymask *
  • filtermask *
  • transformmask *
  • selectionmask *
* * When relevant, the new Node will have the colorspace of the image by default; * that can be changed with Node::setColorSpace. * * The settings and selections for relevant layer and mask types can also be set * after the Node has been created. * @code d = Application.createDocument(1000, 1000, "Test", "RGBA", "U8", "", 120.0) root = d.rootNode(); print(root.childNodes()) l2 = d.createNode("layer2", "paintLayer") print(l2) root.addChildNode(l2, None) print(root.childNodes()) @endcode * * * @return the new Node. */ Node* createNode(const QString &name, const QString &nodeType); /** * @brief createGroupLayer * Returns a grouplayer object. Grouplayers are nodes that can have * other layers as children and have the passthrough mode. * @param name the name of the layer. * @return a GroupLayer object. */ GroupLayer* createGroupLayer(const QString &name); /** * @brief createFileLayer returns a layer that shows an external image. * @param name name of the file layer. * @param fileName the absolute filename of the file referenced. Symlinks will be resolved. * @param scalingMethod how the dimensions of the file are interpreted * can be either "None", "ImageToSize" or "ImageToPPI" * @return a FileLayer */ FileLayer* createFileLayer(const QString &name, const QString fileName, const QString scalingMethod); /** * @brief createFilterLayer creates a filter layer, which is a layer that represents a filter * applied non-destructively. * @param name name of the filterLayer * @param filter the filter that this filter layer will us. * @param selection the selection. * @return a filter layer object. */ FilterLayer* createFilterLayer(const QString &name, Filter &filter, Selection &selection); /** * @brief createFillLayer creates a fill layer object, which is a layer * @param name * @param generatorName - name of the generation filter. * @param configuration - the configuration for the generation filter. * @param selection - the selection. * @return a filllayer object. * * @code * from krita import * * d = Krita.instance().activeDocument() * i = InfoObject(); * i.setProperty("pattern", "Cross01.pat") * s = Selection(); * s.select(0, 0, d.width(), d.height(), 255) * n = d.createFillLayer("test", "pattern", i, s) * r = d.rootNode(); * c = r.childNodes(); * r.addChildNode(n, c[0]) * d.refreshProjection() * @endcode */ FillLayer* createFillLayer(const QString &name, const QString generatorName, InfoObject &configuration, Selection &selection); /** * @brief createCloneLayer * @param name * @param source * @return */ CloneLayer* createCloneLayer(const QString &name, const Node* source); /** * @brief createVectorLayer * Creates a vector layer that can contain vector shapes. * @param name the name of this layer. * @return a VectorLayer. */ VectorLayer* createVectorLayer(const QString &name); /** * @brief createFilterMask * Creates a filter mask object that much like a filterlayer can apply a filter non-destructively. * @param name the name of the layer. * @param filter the filter assigned. * @return a FilterMask */ FilterMask* createFilterMask(const QString &name, Filter &filter); /** * @brief createSelectionMask * Creates a selection mask, which can be used to store selections. * @param name - the name of the layer. * @return a SelectionMask */ SelectionMask* createSelectionMask(const QString &name); /** * @brief projection creates a QImage from the rendered image or * a cutout rectangle. */ QImage projection(int x = 0, int y = 0, int w = 0, int h = 0) const; /** * @brief thumbnail create a thumbnail of the given dimensions. * * If the requested size is too big a null QImage is created. * * @return a QImage representing the layer contents. */ QImage thumbnail(int w, int h) const; /** * Why this should be used, When it should be used, How it should be used, * and warnings about when not. */ void lock(); /** * Why this should be used, When it should be used, How it should be used, * and warnings about when not. */ void unlock(); /** * Why this should be used, When it should be used, How it should be used, * and warnings about when not. */ void waitForDone(); /** * Why this should be used, When it should be used, How it should be used, * and warnings about when not. */ bool tryBarrierLock(); /** * Why this should be used, When it should be used, How it should be used, * and warnings about when not. */ bool isIdle(); /** * Starts a synchronous recomposition of the projection: everything will * wait until the image is fully recomputed. */ void refreshProjection(); /** * @brief setHorizontalGuides * replace all existing horizontal guides with the entries in the list. - * @param list a list of floats containing the new guides. + * @param lines a list of floats containing the new guides. */ void setHorizontalGuides(const QList &lines); /** * @brief setVerticalGuides * replace all existing horizontal guides with the entries in the list. - * @param list a list of floats containing the new guides. + * @param lines a list of floats containing the new guides. */ void setVerticalGuides(const QList &lines); /** * @brief setGuidesVisible * set guides visible on this document. * @param visible whether or not the guides are visible. */ void setGuidesVisible(bool visible); /** * @brief setGuidesLocked * set guides locked on this document * @param locked whether or not to lock the guides on this document. */ void setGuidesLocked(bool locked); /** * @brief modified returns true if the document has unsaved modifications. */ bool modified() const; /** * @brief bounds return the bounds of the image * @return the bounds */ QRect bounds() const; /**** * Animation Related API *****/ /** * @brief Import an image sequence of files from a directory. This will grab all * images from the directory and import them with a potential offset (firstFrame) * and step (images on 2s, 3s, etc) * @returns whether the animation import was successful */ bool importAnimation(const QList &files, int firstFrame, int step); /** * @brief frames per second of document * @return the fps of the document */ int framesPerSecond(); /** * @brief set frames per second of document */ void setFramesPerSecond(int fps); /** * @brief set start time of animation */ void setFullClipRangeStartTime(int startTime); /** * @brief get the full clip range start time * @return full clip range start time */ int fullClipRangeStartTime(); /** * @brief set full clip range end time */ void setFullClipRangeEndTime(int endTime); /** * @brief get the full clip range end time * @return full clip range end time */ int fullClipRangeEndTime(); /** * @brief get total frame range for animation * @return total frame range for animation */ int animationLength(); /** * @brief set temporary playback range of document */ void setPlayBackRange(int start, int stop); /** * @brief get start time of current playback * @return start time of current playback */ int playBackStartTime(); /** * @brief get end time of current playback * @return end time of current playback */ int playBackEndTime(); /** * @brief get current frame selected of animation * @return current frame selected of animation */ int currentTime(); /** * @brief set current time of document's animation */ void setCurrentTime(int time); private: friend class Krita; friend class Window; friend class Filter; QPointer document() const; private: struct Private; Private *const d; }; #endif // LIBKIS_DOCUMENT_H diff --git a/libs/libkis/Extension.h b/libs/libkis/Extension.h index eb9502a953..911792901a 100644 --- a/libs/libkis/Extension.h +++ b/libs/libkis/Extension.h @@ -1,86 +1,86 @@ /* * Copyright (c) 2015 Cyrille Berger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 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 Lesser 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 LIBKIS_EXTENSION_H #define LIBKIS_EXTENSION_H #include "kritalibkis_export.h" #include #include /** * An Extension is the base for classes that extend Krita. An Extension * is loaded on startup, when the setup() method will be executed. * * The extension instance should be added to the Krita Application object * using Krita.instance().addViewExtension or Application.addViewExtension * or Scripter.addViewExtension. * * Example: * * @code * import sys * from PyQt5.QtGui import * * from PyQt5.QtWidgets import * * from krita import * * class HelloExtension(Extension): * * def __init__(self, parent): * super().__init__(parent) * * def hello(self): * QMessageBox.information(QWidget(), "Test", "Hello! This is Krita " + Application.version()) * * def setup(self): * qDebug("Hello Setup") * * def createActions(self, window) * action = window.createAction("hello") * action.triggered.connect(self.hello) * * Scripter.addExtension(HelloExtension(Krita.instance())) * * @endcode */ class KRITALIBKIS_EXPORT Extension : public QObject { Q_OBJECT public: /** * Create a new extension. The extension will be - * owned by @param parent. + * owned by @p parent. */ explicit Extension(QObject *parent = 0); ~Extension() override; /** * Override this function to setup your Extension. You can use it to integrate * with the Krita application instance. */ virtual void setup() = 0; virtual void createActions(Window *window) = 0; }; #endif diff --git a/libs/libkis/FileLayer.h b/libs/libkis/FileLayer.h index 1468345c4b..6e9ec8178a 100644 --- a/libs/libkis/FileLayer.h +++ b/libs/libkis/FileLayer.h @@ -1,106 +1,108 @@ /* * Copyright (c) 2017 Wolthera van Hövell tot Westerflier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 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 Lesser 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 LIBKIS_FILELAYER_H #define LIBKIS_FILELAYER_H #include #include "Node.h" #include #include "kritalibkis_export.h" #include "libkis.h" /** * @brief The FileLayer class * A file layer is a layer that can reference an external image * and show said reference in the layer stack. * * If the external image is updated, Krita will try to update the * file layer image as well. */ class KRITALIBKIS_EXPORT FileLayer : public Node { Q_OBJECT Q_DISABLE_COPY(FileLayer) public: explicit FileLayer(KisImageSP image, const QString name = QString(), const QString baseName=QString(), const QString fileName=QString(), const QString scalingMethod=QString(), QObject *parent = 0); explicit FileLayer(KisFileLayerSP layer, QObject *parent = 0); ~FileLayer() override; public Q_SLOTS: /** * @brief type Krita has several types of nodes, split in layers and masks. Group * layers can contain other layers, any layer can contain masks. * * @return "filelayer" */ QString type() const override; /** * @brief setProperties * Change the properties of the file layer. * @param fileName - A String containing the absolute file name. * @param scalingMethod - a string with the scaling method, defaults to "None", * other options are "ToImageSize" and "ToImagePPI" */ void setProperties(QString fileName, QString scalingMethod = QString("None")); /** * @brief makes the file layer to reload the connected image from disk */ void resetCache(); /** * @brief path * @return A QString with the full path of the referenced image. */ QString path() const; /** * @brief scalingMethod * returns how the file referenced is scaled. * @return one of the following: + *
    *
  • None - The file is not scaled in any way. *
  • ToImageSize - The file is scaled to the full image size; *
  • ToImagePPI - The file is scaled by the PPI of the image. This keep the physical dimensions the same. + *
*/ QString scalingMethod() const; private: /** * @brief getFileNameFromAbsolute * referenced from the fileLayer dialog, this will jumps through all the hoops * to ensure that an appropriate filename will be gotten. * @param baseName the location of the document. * @param absolutePath the absolute location of the file referenced. * @return the appropriate relative path. */ QString getFileNameFromAbsolute(const QString &basePath, QString filePath); QString m_baseName; }; #endif // LIBKIS_FILELAYER_H diff --git a/libs/libkis/Filter.h b/libs/libkis/Filter.h index a81aaa39cf..ba885a25d0 100644 --- a/libs/libkis/Filter.h +++ b/libs/libkis/Filter.h @@ -1,114 +1,120 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 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 Lesser 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 LIBKIS_FILTER_H #define LIBKIS_FILTER_H #include #include "kritalibkis_export.h" #include "libkis.h" #include /** * Filter: represents a filter and its configuration. A filter is identified by * an internal name. The configuration for each filter is defined as an InfoObject: * a map of name and value pairs. * * Currently available filters are: * * 'autocontrast', 'blur', 'bottom edge detections', 'brightnesscontrast', 'burn', 'colorbalance', 'colortoalpha', 'colortransfer', * 'desaturate', 'dodge', 'emboss', 'emboss all directions', 'emboss horizontal and vertical', 'emboss horizontal only', * 'emboss laplascian', 'emboss vertical only', 'gaussian blur', 'gaussiannoisereducer', 'gradientmap', 'halftone', 'hsvadjustment', * 'indexcolors', 'invert', 'left edge detections', 'lens blur', 'levels', 'maximize', 'mean removal', 'minimize', 'motion blur', * 'noise', 'normalize', 'oilpaint', 'perchannel', 'phongbumpmap', 'pixelize', 'posterize', 'raindrops', 'randompick', * 'right edge detections', 'roundcorners', 'sharpen', 'smalltiles', 'sobel', 'threshold', 'top edge detections', 'unsharp', * 'wave', 'waveletnoisereducer'] */ class KRITALIBKIS_EXPORT Filter : public QObject { Q_OBJECT Q_DISABLE_COPY(Filter) public: /** * @brief Filter: create an empty filter object. Until a name is set, the filter cannot * be applied. */ explicit Filter(); ~Filter() override; bool operator==(const Filter &other) const; bool operator!=(const Filter &other) const; public Q_SLOTS: /** * @brief name the internal name of this filter. * @return the name. */ QString name() const; /** * @brief setName set the filter's name to the given name. */ void setName(const QString &name); /** * @return the configuration object for the filter */ InfoObject* configuration() const; /** * @brief setConfiguration set the configuration object for the filter */ void setConfiguration(InfoObject* value); /** * @brief Apply the filter to the given node. * @param node the node to apply the filter to - * @params x, y, w, h: describe the rectangle the filter should be apply. + * @param x + * @param y + * @param w + * @param h describe the rectangle the filter should be apply. * This is always in image pixel coordinates and not relative to the x, y * of the node. - * @return true if the filter was applied successfully, or - * false if the filter could not be applied because the node is locked or + * @return @c true if the filter was applied successfully, or + * @c false if the filter could not be applied because the node is locked or * does not have an editable paint device. */ bool apply(Node *node, int x, int y, int w, int h); /** * @brief startFilter starts the given filter on the given node. * * @param node the node to apply the filter to - * @params x, y, w, h: describe the rectangle the filter should be apply. + * @param x + * @param y + * @param w + * @param h describe the rectangle the filter should be apply. * This is always in image pixel coordinates and not relative to the x, y * of the node. */ bool startFilter(Node *node, int x, int y, int w, int h); private: friend class FilterLayer; friend class FilterMask; struct Private; Private *const d; KisFilterConfigurationSP filterConfig(); }; #endif // LIBKIS_FILTER_H diff --git a/libs/libkis/InfoObject.h b/libs/libkis/InfoObject.h index 6330557424..ee8c4b9ff7 100644 --- a/libs/libkis/InfoObject.h +++ b/libs/libkis/InfoObject.h @@ -1,88 +1,88 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 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 Lesser 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 LIBKIS_INFOOBJECT_H #define LIBKIS_INFOOBJECT_H #include #include #include "kritalibkis_export.h" #include "libkis.h" /** * InfoObject wrap a properties map. These maps can be used to set the * configuration for filters. */ class KRITALIBKIS_EXPORT InfoObject : public QObject { Q_OBJECT public: InfoObject(KisPropertiesConfigurationSP configuration); /** * Create a new, empty InfoObject. */ explicit InfoObject(QObject *parent = 0); ~InfoObject() override; bool operator==(const InfoObject &other) const; bool operator!=(const InfoObject &other) const; /** * Return all properties this InfoObject manages. */ QMap properties() const; /** - * Add all properties in the @param propertyMap to this InfoObject + * Add all properties in the @p propertyMap to this InfoObject */ - void setProperties(QMap proprertyMap); + void setProperties(QMap propertyMap); public Q_SLOTS: /** - * set the property identified by @key to @value + * set the property identified by @p key to @p value * * If you want create a property that represents a color, you can use a QColor * or hex string, as defined in http://doc.qt.io/qt-5/qcolor.html#setNamedColor. * */ void setProperty(const QString &key, QVariant value); /** * return the value for the property identified by key, or None if there is no such key. */ QVariant property(const QString &key); private: friend class Filter; friend class Document; friend class Node; /** * @brief configuration gives access to the internal configuration object. Must * be used used internally in libkis * @return the internal configuration object. */ KisPropertiesConfigurationSP configuration() const; struct Private; Private *d; }; #endif // LIBKIS_INFOOBJECT_H diff --git a/libs/libkis/ManagedColor.h b/libs/libkis/ManagedColor.h index 190a7e00bd..5b5837ee17 100644 --- a/libs/libkis/ManagedColor.h +++ b/libs/libkis/ManagedColor.h @@ -1,212 +1,211 @@ /* * Copyright (C) 2017 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef MANAGEDCOLOR_H #define MANAGEDCOLOR_H #include #include #include #include "kritalibkis_export.h" #include "libkis.h" class KoColor; /** * @brief The ManagedColor class is a class to handle colors that are color managed. * A managed color is a color of which we know the model(RGB, LAB, CMYK, etc), the bitdepth and * the specific properties of its colorspace, such as the whitepoint, chromacities, trc, etc, as represented * by the color profile. * * Krita has two color management systems. LCMS and OCIO. * LCMS is the one handling the ICC profile stuff, and the major one handling that ManagedColor deals with. * OCIO support is only in the display of the colors. ManagedColor has some support for it in colorForCanvas() * * All colors in Krita are color managed. QColors are understood as RGB-type colors in the sRGB space. * * We recommend you make a color like this: * * @code * colorYellow = ManagedColor("RGBA", "U8", "") * QVector yellowComponents = colorYellow.components() * yellowComponents[0] = 1.0 * yellowComponents[1] = 1.0 * yellowComponents[2] = 0 * yellowComponents[3] = 1.0 * * colorYellow.setComponents(yellowComponents) * QColor yellow = colorYellow.colorForCanvas(canvas) * @endcode */ class KRITALIBKIS_EXPORT ManagedColor : public QObject { Q_OBJECT public: /** * @brief ManagedColor * Create a ManagedColor that is black and transparent. */ explicit ManagedColor(QObject *parent = 0); /** * @brief ManagedColor create a managed color with the given color space properties. * @see setColorModel() for more details. */ ManagedColor(const QString &colorModel, const QString &colorDepth, const QString &colorProfile, QObject *parent = 0); ManagedColor(KoColor color, QObject *parent = 0); ~ManagedColor() override; bool operator==(const ManagedColor &other) const; /** * @brief colorForCanvas * @param canvas the canvas whose color management you'd like to use. In Krita, different views have * separate canvasses, and these can have different OCIO configurations active. * @return the QColor as it would be displaying on the canvas. This result can be used to draw widgets with * the correct configuration applied. */ QColor colorForCanvas(Canvas *canvas) const; /** * colorDepth A string describing the color depth of the image: *
    *
  • U8: unsigned 8 bits integer, the most common type
  • *
  • U16: unsigned 16 bits integer
  • *
  • F16: half, 16 bits floating point. Only available if Krita was built with OpenEXR
  • *
  • F32: 32 bits floating point
  • *
* @return the color depth. */ QString colorDepth() const; /** * @brief colorModel retrieve the current color model of this document: *
    *
  • A: Alpha mask
  • *
  • RGBA: RGB with alpha channel (The actual order of channels is most often BGR!)
  • *
  • XYZA: XYZ with alpha channel
  • *
  • LABA: LAB with alpha channel
  • *
  • CMYKA: CMYK with alpha channel
  • *
  • GRAYA: Gray with alpha channel
  • *
  • YCbCrA: YCbCr with alpha channel
  • *
* @return the internal color model string. */ QString colorModel() const; /** * @return the name of the current color profile */ QString colorProfile() const; /** * @brief setColorProfile set the color profile of the image to the given profile. The profile has to * be registered with krita and be compatible with the current color model and depth; the image data * is not converted. * @param colorProfile * @return false if the colorProfile name does not correspond to to a registered profile or if assigning * the profile failed. */ bool setColorProfile(const QString &colorProfile); /** * @brief setColorSpace convert the nodes and the image to the given colorspace. The conversion is * done with Perceptual as intent, High Quality and No LCMS Optimizations as flags and no blackpoint * compensation. * * @param colorModel A string describing the color model of the image: *
    *
  • A: Alpha mask
  • *
  • RGBA: RGB with alpha channel (The actual order of channels is most often BGR!)
  • *
  • XYZA: XYZ with alpha channel
  • *
  • LABA: LAB with alpha channel
  • *
  • CMYKA: CMYK with alpha channel
  • *
  • GRAYA: Gray with alpha channel
  • *
  • YCbCrA: YCbCr with alpha channel
  • *
* @param colorDepth A string describing the color depth of the image: *
    *
  • U8: unsigned 8 bits integer, the most common type
  • *
  • U16: unsigned 16 bits integer
  • *
  • F16: half, 16 bits floating point. Only available if Krita was built with OpenEXR
  • *
  • F32: 32 bits floating point
  • *
* @param colorProfile a valid color profile for this color model and color depth combination. * @return false the combination of these arguments does not correspond to a colorspace. */ bool setColorSpace(const QString &colorModel, const QString &colorDepth, const QString &colorProfile); /** * @brief components * @return a QVector containing the channel/components of this color normalized. This includes the alphachannel. */ QVector components() const; /** * @brief componentsOrdered() * @return same as Components, except the values are ordered to the display. */ QVector componentsOrdered() const; /** * @brief setComponents * Set the channel/components with normalized values. For integer colorspace, this obviously means the limit * is between 0.0-1.0, but for floating point colorspaces, 2.4 or 103.5 are still meaningful (if bright) values. * @param values the QVector containing the new channel/component values. These should be normalized. */ void setComponents(const QVector &values); /** * Serialize this color following Create's swatch color specification available * at http://create.freedesktop.org/wiki/index.php/Swatches_-_colour_file_format */ QString toXML() const; /** * Unserialize a color following Create's swatch color specification available * at http://create.freedesktop.org/wiki/index.php/Swatches_-_colour_file_format * - * @param XXX + * @param xml an XML color * * @return the unserialized color, or an empty color object if the function failed * to unserialize the color */ void fromXML(const QString &xml); /** * @brief toQString create a user-visible string of the channel names and the channel values - * @param color the color to create the string from * @return a string that can be used to display the values of this color to the user. */ QString toQString(); private: friend class View; friend class PaletteView; friend class Swatch; KoColor color() const; struct Private; const QScopedPointer d; }; #endif // MANAGEDCOLOR_H diff --git a/libs/libkis/Node.cpp b/libs/libkis/Node.cpp index 3ea3f11753..75361fb784 100644 --- a/libs/libkis/Node.cpp +++ b/libs/libkis/Node.cpp @@ -1,628 +1,646 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 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 Lesser 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 #include #include #include #include #include #include #include #include #include "kis_selection.h" #include "InfoObject.h" #include "Krita.h" #include "Node.h" #include "Channel.h" #include "Filter.h" #include "Selection.h" #include "GroupLayer.h" #include "CloneLayer.h" #include "FilterLayer.h" #include "FillLayer.h" #include "FileLayer.h" #include "VectorLayer.h" #include "FilterMask.h" #include "SelectionMask.h" #include "LibKisUtils.h" struct Node::Private { Private() {} KisImageWSP image; KisNodeSP node; }; Node::Node(KisImageSP image, KisNodeSP node, QObject *parent) : QObject(parent) , d(new Private) { d->image = image; d->node = node; } Node::~Node() { delete d; } bool Node::operator==(const Node &other) const { return (d->node == other.d->node && d->image == other.d->image); } bool Node::operator!=(const Node &other) const { return !(operator==(other)); } Node *Node::clone() const { KisNodeSP clone = d->node->clone(); Node *node = new Node(0, clone); return node; } bool Node::alphaLocked() const { if (!d->node) return false; KisPaintLayerSP paintLayer = qobject_cast(d->node.data()); if (paintLayer) { return paintLayer->alphaLocked(); } return false; } void Node::setAlphaLocked(bool value) { if (!d->node) return; KisPaintLayerSP paintLayer = qobject_cast(d->node.data()); if (paintLayer) { paintLayer->setAlphaLocked(value); } } QString Node::blendingMode() const { if (!d->node) return QString(); return d->node->compositeOpId(); } void Node::setBlendingMode(QString value) { if (!d->node) return; d->node->setCompositeOpId(value); } QList Node::channels() const { QList channels; if (!d->node) return channels; if (!d->node->inherits("KisLayer")) return channels; Q_FOREACH(KoChannelInfo *info, d->node->colorSpace()->channels()) { Channel *channel = new Channel(d->node, info); channels << channel; } return channels; } QList Node::childNodes() const { QList nodes; if (d->node) { KisNodeList nodeList; int childCount = d->node->childCount(); for (int i = 0; i < childCount; ++i) { nodeList << d->node->at(i); } nodes = LibKisUtils::createNodeList(nodeList, d->image); } return nodes; } bool Node::addChildNode(Node *child, Node *above) { if (!d->node) return false; if (above) { return d->image->addNode(child->node(), d->node, above->node()); } else { return d->image->addNode(child->node(), d->node, d->node->childCount()); } } bool Node::removeChildNode(Node *child) { if (!d->node) return false; return d->image->removeNode(child->node()); } void Node::setChildNodes(QList nodes) { if (!d->node) return; KisNodeSP node = d->node->firstChild(); while (node) { d->image->removeNode(node); node = node->nextSibling(); } Q_FOREACH(Node *node, nodes) { d->image->addNode(node->node(), d->node); } } int Node::colorLabel() const { if (!d->node) return 0; return d->node->colorLabelIndex(); } void Node::setColorLabel(int index) { if (!d->node) return; d->node->setColorLabelIndex(index); } QString Node::colorDepth() const { if (!d->node) return ""; return d->node->colorSpace()->colorDepthId().id(); } QString Node::colorModel() const { if (!d->node) return ""; return d->node->colorSpace()->colorModelId().id(); } QString Node::colorProfile() const { if (!d->node) return ""; return d->node->colorSpace()->profile()->name(); } bool Node::setColorProfile(const QString &colorProfile) { if (!d->node) return false; if (!d->node->inherits("KisLayer")) return false; KisLayer *layer = qobject_cast(d->node.data()); const KoColorProfile *profile = KoColorSpaceRegistry::instance()->profileByName(colorProfile); const KoColorSpace *srcCS = layer->colorSpace(); const KoColorSpace *dstCs = KoColorSpaceRegistry::instance()->colorSpace(srcCS->colorModelId().id(), srcCS->colorDepthId().id(), profile); KisChangeProfileVisitor v(srcCS, dstCs); return layer->accept(v); } bool Node::setColorSpace(const QString &colorModel, const QString &colorDepth, const QString &colorProfile) { if (!d->node) return false; if (!d->node->inherits("KisLayer")) return false; KisLayer *layer = qobject_cast(d->node.data()); const KoColorProfile *profile = KoColorSpaceRegistry::instance()->profileByName(colorProfile); const KoColorSpace *srcCS = layer->colorSpace(); const KoColorSpace *dstCs = KoColorSpaceRegistry::instance()->colorSpace(colorModel, colorDepth, profile); KisColorSpaceConvertVisitor v(d->image, srcCS, dstCs, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); return layer->accept(v); } bool Node::animated() const { if (!d->node) return false; return d->node->isAnimated(); } void Node::enableAnimation() const { if (!d->node) return; d->node->enableAnimation(); } void Node::setShowInTimeline(bool showInTimeline) const { if (!d->node) return; d->node->setUseInTimeline(showInTimeline); } bool Node::showInTimeline() const { if (!d->node) return false; return d->node->useInTimeline(); } bool Node::collapsed() const { if (!d->node) return false; return d->node->collapsed(); } void Node::setCollapsed(bool collapsed) { if (!d->node) return; d->node->setCollapsed(collapsed); } bool Node::inheritAlpha() const { if (!d->node) return false; if (!d->node->inherits("KisLayer")) return false; return qobject_cast(d->node)->alphaChannelDisabled(); } void Node::setInheritAlpha(bool value) { if (!d->node) return; if (!d->node->inherits("KisLayer")) return; const_cast(qobject_cast(d->node))->disableAlphaChannel(value); } bool Node::locked() const { if (!d->node) return false; return d->node->userLocked(); } void Node::setLocked(bool value) { if (!d->node) return; d->node->setUserLocked(value); } bool Node::hasExtents() { return !d->node->extent().isEmpty(); } QString Node::name() const { if (!d->node) return QString(); return d->node->name(); } void Node::setName(QString name) { if (!d->node) return; d->node->setName(name); } int Node::opacity() const { if (!d->node) return 0; return d->node->opacity(); } void Node::setOpacity(int value) { if (!d->node) return; if (value < 0) value = 0; if (value > 255) value = 255; d->node->setOpacity(value); } Node* Node::parentNode() const { if (!d->node) return 0; return new Node(d->image, d->node->parent()); } QString Node::type() const { if (!d->node) return QString(); if (qobject_cast(d->node)) { return "paintlayer"; } else if (qobject_cast(d->node)) { return "grouplayer"; } if (qobject_cast(d->node)) { return "filelayer"; } if (qobject_cast(d->node)) { return "filterlayer"; } if (qobject_cast(d->node)) { return "filllayer"; } if (qobject_cast(d->node)) { return "clonelayer"; } if (qobject_cast(d->node)) { return "referenceimageslayer"; } if (qobject_cast(d->node)) { return "vectorlayer"; } if (qobject_cast(d->node)) { return "transparencymask"; } if (qobject_cast(d->node)) { return "filtermask"; } if (qobject_cast(d->node)) { return "transformmask"; } if (qobject_cast(d->node)) { return "selectionmask"; } if (qobject_cast(d->node)) { return "colorizemask"; } return QString(); } QIcon Node::icon() const { QIcon icon; if (d->node) { icon = d->node->icon(); } return icon; } bool Node::visible() const { if (!d->node) return false; return d->node->visible(); } +bool Node::hasKeyframeAtTime(int frameNumber) +{ + if (!d->node || !d->node->isAnimated()) return false; + + KisRasterKeyframeChannel *rkc = dynamic_cast(d->node->getKeyframeChannel(KisKeyframeChannel::Content.id())); + if (!rkc) return false; + + KisKeyframeSP timeOfCurrentKeyframe = rkc->keyframeAt(frameNumber); + + if (!timeOfCurrentKeyframe) { + return false; + } + + // do an assert just to be careful + KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(timeOfCurrentKeyframe->time() == frameNumber, false); + return true; +} + void Node::setVisible(bool visible) { if (!d->node) return; d->node->setVisible(visible); } QByteArray Node::pixelData(int x, int y, int w, int h) const { QByteArray ba; if (!d->node) return ba; KisPaintDeviceSP dev = d->node->paintDevice(); if (!dev) return ba; ba.resize(w * h * dev->pixelSize()); dev->readBytes(reinterpret_cast(ba.data()), x, y, w, h); return ba; } QByteArray Node::pixelDataAtTime(int x, int y, int w, int h, int time) const { QByteArray ba; if (!d->node || !d->node->isAnimated()) return ba; // KisRasterKeyframeChannel *rkc = dynamic_cast(d->node->getKeyframeChannel(KisKeyframeChannel::Content.id())); if (!rkc) return ba; KisKeyframeSP frame = rkc->keyframeAt(time); if (!frame) return ba; KisPaintDeviceSP dev = d->node->paintDevice(); if (!dev) return ba; rkc->fetchFrame(frame, dev); ba.resize(w * h * dev->pixelSize()); dev->readBytes(reinterpret_cast(ba.data()), x, y, w, h); return ba; } QByteArray Node::projectionPixelData(int x, int y, int w, int h) const { QByteArray ba; if (!d->node) return ba; KisPaintDeviceSP dev = d->node->projection(); ba.resize(w * h * dev->pixelSize()); dev->readBytes(reinterpret_cast(ba.data()), x, y, w, h); return ba; } void Node::setPixelData(QByteArray value, int x, int y, int w, int h) { if (!d->node) return; KisPaintDeviceSP dev = d->node->paintDevice(); if (!dev) return; dev->writeBytes((const quint8*)value.constData(), x, y, w, h); } QRect Node::bounds() const { if (!d->node) return QRect(); return d->node->exactBounds(); } void Node::move(int x, int y) { if (!d->node) return; d->node->setX(x); d->node->setY(y); } QPoint Node::position() const { if (!d->node) return QPoint(); return QPoint(d->node->x(), d->node->y()); } bool Node::remove() { if (!d->node) return false; if (!d->node->parent()) return false; return d->image->removeNode(d->node); } Node* Node::duplicate() { if (!d->node) return 0; return new Node(d->image, d->node->clone()); } bool Node::save(const QString &filename, double xRes, double yRes, const InfoObject &exportConfiguration) { if (!d->node) return false; if (filename.isEmpty()) return false; KisPaintDeviceSP projection = d->node->projection(); QRect bounds = d->node->exactBounds(); QString mimeType = KisMimeDatabase::mimeTypeForFile(filename, false); QScopedPointer doc(KisPart::instance()->createDocument()); KisImageSP dst = new KisImage(doc->createUndoStore(), bounds.right(), bounds.bottom(), projection->compositionSourceColorSpace(), d->node->name()); dst->setResolution(xRes, yRes); doc->setFileBatchMode(Krita::instance()->batchmode()); doc->setCurrentImage(dst); KisPaintLayer* paintLayer = new KisPaintLayer(dst, "paint device", d->node->opacity()); paintLayer->paintDevice()->makeCloneFrom(projection, bounds); dst->addNode(paintLayer, dst->rootLayer(), KisLayerSP(0)); dst->cropImage(bounds); dst->initialRefreshGraph(); bool r = doc->exportDocumentSync(QUrl::fromLocalFile(filename), mimeType.toLatin1(), exportConfiguration.configuration()); if (!r) { qWarning() << doc->errorMessage(); } return r; } Node* Node::mergeDown() { if (!d->node) return 0; if (!qobject_cast(d->node.data())) return 0; if (!d->node->prevSibling()) return 0; d->image->mergeDown(qobject_cast(d->node.data()), KisMetaData::MergeStrategyRegistry::instance()->get("Drop")); d->image->waitForDone(); return new Node(d->image, d->node->prevSibling()); } void Node::scaleNode(QPointF origin, int width, int height, QString strategy) { if (!d->node) return; if (!qobject_cast(d->node.data())) return; if (!d->node->parent()) return; KisFilterStrategy *actualStrategy = KisFilterStrategyRegistry::instance()->get(strategy); if (!actualStrategy) actualStrategy = KisFilterStrategyRegistry::instance()->get("Bicubic"); const QRect bounds(d->node->exactBounds()); d->image->scaleNode(d->node, origin, qreal(width) / bounds.width(), qreal(height) / bounds.height(), actualStrategy, 0); } void Node::rotateNode(double radians) { if (!d->node) return; if (!qobject_cast(d->node.data())) return; if (!d->node->parent()) return; d->image->rotateNode(d->node, radians, 0); } void Node::cropNode(int x, int y, int w, int h) { if (!d->node) return; if (!qobject_cast(d->node.data())) return; if (!d->node->parent()) return; QRect rect = QRect(x, y, w, h); d->image->cropNode(d->node, rect); } void Node::shearNode(double angleX, double angleY) { if (!d->node) return; if (!qobject_cast(d->node.data())) return; if (!d->node->parent()) return; d->image->shearNode(d->node, angleX, angleY, 0); } QImage Node::thumbnail(int w, int h) { if (!d->node) return QImage(); return d->node->createThumbnail(w, h); } KisPaintDeviceSP Node::paintDevice() const { return d->node->paintDevice(); } KisImageSP Node::image() const { return d->image; } KisNodeSP Node::node() const { return d->node; } diff --git a/libs/libkis/Node.h b/libs/libkis/Node.h index 02b2f546c5..c9723f30f2 100644 --- a/libs/libkis/Node.h +++ b/libs/libkis/Node.h @@ -1,564 +1,570 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 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 Lesser 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 LIBKIS_NODE_H #define LIBKIS_NODE_H #include #include #include "kritalibkis_export.h" #include "libkis.h" /** * Node represents a layer or mask in a Krita image's Node hierarchy. Group layers can contain * other layers and masks; layers can contain masks. * */ class KRITALIBKIS_EXPORT Node : public QObject { Q_OBJECT Q_DISABLE_COPY(Node) public: explicit Node(KisImageSP image, KisNodeSP node, QObject *parent = 0); ~Node() override; bool operator==(const Node &other) const; bool operator!=(const Node &other) const; public Q_SLOTS: /** * @brief clone clone the current node. The node is not associated with any image. */ Node *clone() const; /** * @brief alphaLocked checks whether the node is a paint layer and returns whether it is alpha locked * @return whether the paint layer is alpha locked, or false if the node is not a paint layer */ bool alphaLocked() const; /** * @brief setAlphaLocked set the layer to value if the node is paint layer. */ void setAlphaLocked(bool value); /** * @return the blending mode of the layer. The values of the blending modes are defined in @see KoCompositeOpRegistry.h */ QString blendingMode() const; /** * @brief setBlendingMode set the blending mode of the node to the given value * @param value one of the string values from @see KoCompositeOpRegistry.h */ void setBlendingMode(QString value); /** * @brief channels creates a list of Channel objects that can be used individually to * show or hide certain channels, and to retrieve the contents of each channel in a * node separately. * * Only layers have channels, masks do not, and calling channels on a Node that is a mask * will return an empty list. * * @return the list of channels ordered in by position of the channels in pixel position */ QList channels() const; /** * Return a list of child nodes of the current node. The nodes are ordered from the bottommost up. * The function is not recursive. */ QList childNodes() const; /** * @brief addChildNode adds the given node in the list of children. * @param child the node to be added * @param above the node above which this node will be placed * @return false if adding the node failed */ bool addChildNode(Node *child, Node *above); /** * @brief removeChildNode removes the given node from the list of children. * @param child the node to be removed */ bool removeChildNode(Node *child); /** * @brief setChildNodes this replaces the existing set of child nodes with the new set. * @param nodes The list of nodes that will become children, bottom-up -- the first node, * is the bottom-most node in the stack. */ void setChildNodes(QList nodes); /** * colorDepth A string describing the color depth of the image: *
    *
  • U8: unsigned 8 bits integer, the most common type
  • *
  • U16: unsigned 16 bits integer
  • *
  • F16: half, 16 bits floating point. Only available if Krita was built with OpenEXR
  • *
  • F32: 32 bits floating point
  • *
* @return the color depth. */ QString colorDepth() const; /** * @brief colorModel retrieve the current color model of this document: *
    *
  • A: Alpha mask
  • *
  • RGBA: RGB with alpha channel (The actual order of channels is most often BGR!)
  • *
  • XYZA: XYZ with alpha channel
  • *
  • LABA: LAB with alpha channel
  • *
  • CMYKA: CMYK with alpha channel
  • *
  • GRAYA: Gray with alpha channel
  • *
  • YCbCrA: YCbCr with alpha channel
  • *
* @return the internal color model string. */ QString colorModel() const; /** * @return the name of the current color profile */ QString colorProfile() const; /** * @brief setColorProfile set the color profile of the image to the given profile. The profile has to * be registered with krita and be compatible with the current color model and depth; the image data * is not converted. * @param colorProfile * @return if assigning the color profile worked */ bool setColorProfile(const QString &colorProfile); /** * @brief setColorSpace convert the node to the given colorspace * @param colorModel A string describing the color model of the node: *
    *
  • A: Alpha mask
  • *
  • RGBA: RGB with alpha channel (The actual order of channels is most often BGR!)
  • *
  • XYZA: XYZ with alpha channel
  • *
  • LABA: LAB with alpha channel
  • *
  • CMYKA: CMYK with alpha channel
  • *
  • GRAYA: Gray with alpha channel
  • *
  • YCbCrA: YCbCr with alpha channel
  • *
* @param colorDepth A string describing the color depth of the image: *
    *
  • U8: unsigned 8 bits integer, the most common type
  • *
  • U16: unsigned 16 bits integer
  • *
  • F16: half, 16 bits floating point. Only available if Krita was built with OpenEXR
  • *
  • F32: 32 bits floating point
  • *
* @param colorProfile a valid color profile for this color model and color depth combination. */ bool setColorSpace(const QString &colorModel, const QString &colorDepth, const QString &colorProfile); /** * @brief Krita layers can be animated, i.e., have frames. * @return return true if the layer has frames. Currently, the scripting framework * does not give access to the animation features. */ bool animated() const; /** * @brief enableAnimation make the current layer animated, so it can have frames. */ void enableAnimation() const; /** * @brief Should the node be visible in the timeline. It defaults to false * with new layer */ void setShowInTimeline(bool showInTimeline) const; /** * @return is layer is shown in the timeline */ bool showInTimeline() const; /** * Sets the state of the node to the value of @param collapsed */ void setCollapsed(bool collapsed); /** * returns the collapsed state of this node */ bool collapsed() const; /** * Sets a color label index associated to the layer. The actual * color of the label and the number of available colors is * defined by Krita GUI configuration. */ int colorLabel() const; /** * @brief setColorLabel sets a color label index associated to the layer. The actual * color of the label and the number of available colors is * defined by Krita GUI configuration. * @param index an integer corresponding to the set of available color labels. */ void setColorLabel(int index); /** * @brief inheritAlpha checks whether this node has the inherits alpha flag set * @return true if the Inherit Alpha is set */ bool inheritAlpha() const; /** * set the Inherit Alpha flag to the given value */ void setInheritAlpha(bool value); /** * @brief locked checks whether the Node is locked. A locked node cannot be changed. * @return true if the Node is locked, false if it hasn't been locked. */ bool locked() const; /** * set the Locked flag to the give value */ void setLocked(bool value); /** * @brief does the node have any content in it? * @return if node has any content in it */ bool hasExtents(); /** * @return the user-visible name of this node. */ QString name() const; /** * rename the Node to the given name */ void setName(QString name); /** * return the opacity of the Node. The opacity is a value between 0 and 255. */ int opacity() const; /** * set the opacity of the Node to the given value. The opacity is a value between 0 and 255. */ void setOpacity(int value); /** * return the Node that is the parent of the current Node, or 0 if this is the root Node. */ Node* parentNode() const; /** * @brief type Krita has several types of nodes, split in layers and masks. Group * layers can contain other layers, any layer can contain masks. * * @return The type of the node. Valid types are: *
    *
  • paintlayer *
  • grouplayer *
  • filelayer *
  • filterlayer *
  • filllayer *
  • clonelayer *
  • vectorlayer *
  • transparencymask *
  • filtermask *
  • transformmask *
  • selectionmask *
  • colorizemask *
* * If the Node object isn't wrapping a valid Krita layer or mask object, and * empty string is returned. */ virtual QString type() const; /** * @brief icon * @return the icon associated with the layer. */ QIcon icon() const; /** * Check whether the current Node is visible in the layer stack */ bool visible() const; + /** + * Check to see if frame number on layer is a keyframe + */ + bool hasKeyframeAtTime(int frameNumber); + /** * Set the visibility of the current node to @param visible */ void setVisible(bool visible); /** * @brief pixelData reads the given rectangle from the Node's paintable pixels, if those * exist, and returns it as a byte array. The pixel data starts top-left, and is ordered row-first. * * The byte array can be interpreted as follows: 8 bits images have one byte per channel, * and as many bytes as there are channels. 16 bits integer images have two bytes per channel, * representing an unsigned short. 16 bits float images have two bytes per channel, representing * a half, or 16 bits float. 32 bits float images have four bytes per channel, representing a * float. * * You can read outside the node boundaries; those pixels will be transparent black. * * The order of channels is: * *
    *
  • Integer RGBA: Blue, Green, Red, Alpha *
  • Float RGBA: Red, Green, Blue, Alpha *
  • GrayA: Gray, Alpha *
  • Selection: selectedness *
  • LabA: L, a, b, Alpha *
  • CMYKA: Cyan, Magenta, Yellow, Key, Alpha *
  • XYZA: X, Y, Z, A *
  • YCbCrA: Y, Cb, Cr, Alpha *
* * The byte array is a copy of the original node data. In Python, you can use bytes, bytearray * and the struct module to interpret the data and construct, for instance, a Pillow Image object. * * If you read the pixeldata of a mask, a filter or generator layer, you get the selection bytes, * which is one channel with values in the range from 0..255. * * If you want to change the pixels of a node you can write the pixels back after manipulation * with setPixelData(). This will only succeed on nodes with writable pixel data, e.g not on groups * or file layers. * * @param x x position from where to start reading * @param y y position from where to start reading * @param w row length to read * @param h number of rows to read * @return a QByteArray with the pixel data. The byte array may be empty. */ QByteArray pixelData(int x, int y, int w, int h) const; /** * @brief pixelDataAtTime a basic function to get pixeldata from an animated node at a given time. * @param x the position from the left to start reading. * @param y the position from the top to start reader * @param w the row length to read * @param h the number of rows to read * @param time the frame number * @return a QByteArray with the pixel data. The byte array may be empty. */ QByteArray pixelDataAtTime(int x, int y, int w, int h, int time) const; /** * @brief projectionPixelData reads the given rectangle from the Node's projection (that is, what the node * looks like after all sub-Nodes (like layers in a group or masks on a layer) have been applied, * and returns it as a byte array. The pixel data starts top-left, and is ordered row-first. * * The byte array can be interpreted as follows: 8 bits images have one byte per channel, * and as many bytes as there are channels. 16 bits integer images have two bytes per channel, * representing an unsigned short. 16 bits float images have two bytes per channel, representing * a half, or 16 bits float. 32 bits float images have four bytes per channel, representing a * float. * * You can read outside the node boundaries; those pixels will be transparent black. * * The order of channels is: * *
    *
  • Integer RGBA: Blue, Green, Red, Alpha *
  • Float RGBA: Red, Green, Blue, Alpha *
  • GrayA: Gray, Alpha *
  • Selection: selectedness *
  • LabA: L, a, b, Alpha *
  • CMYKA: Cyan, Magenta, Yellow, Key, Alpha *
  • XYZA: X, Y, Z, A *
  • YCbCrA: Y, Cb, Cr, Alpha *
* * The byte array is a copy of the original node data. In Python, you can use bytes, bytearray * and the struct module to interpret the data and construct, for instance, a Pillow Image object. * * If you read the projection of a mask, you get the selection bytes, which is one channel with * values in the range from 0..255. * * If you want to change the pixels of a node you can write the pixels back after manipulation * with setPixelData(). This will only succeed on nodes with writable pixel data, e.g not on groups * or file layers. * * @param x x position from where to start reading * @param y y position from where to start reading * @param w row length to read * @param h number of rows to read * @return a QByteArray with the pixel data. The byte array may be empty. */ QByteArray projectionPixelData(int x, int y, int w, int h) const; /** * @brief setPixelData writes the given bytes, of which there must be enough, into the * Node, if the Node has writable pixel data: * *
    *
  • paint layer: the layer's original pixels are overwritten *
  • filter layer, generator layer, any mask: the embedded selection's pixels are overwritten. * Note: for these *
* * File layers, Group layers, Clone layers cannot be written to. Calling setPixelData on * those layer types will silently do nothing. * * @param value the byte array representing the pixels. There must be enough bytes available. * Krita will take the raw pointer from the QByteArray and start reading, not stopping before * (number of channels * size of channel * w * h) bytes are read. * * @param x the x position to start writing from * @param y the y position to start writing from * @param w the width of each row * @param h the number of rows to write */ void setPixelData(QByteArray value, int x, int y, int w, int h); /** * @brief bounds return the exact bounds of the node's paint device * @return the bounds, or an empty QRect if the node has no paint device or is empty. */ QRect bounds() const; /** * move the pixels to the given x, y location in the image coordinate space. */ void move(int x, int y); /** * @brief position returns the position of the paint device of this node. The position is * always 0,0 unless the layer has been moved. If you want to know the topleft position of * the rectangle around the actual non-transparent pixels in the node, use bounds(). * @return the top-left position of the node */ QPoint position() const; /** * @brief remove removes this node from its parent image. */ bool remove(); /** * @brief duplicate returns a full copy of the current node. The node is not inserted in the graphic * @return a valid Node object or 0 if the node couldn't be duplicated. */ Node* duplicate(); /** * @brief save exports the given node with this filename. The extension of the filename determines the filetype. * @param filename the filename including extension * @param xRes the horizontal resolution in pixels per pt (there are 72 pts in an inch) * @param yRes the horizontal resolution in pixels per pt (there are 72 pts in an inch) * @param exportConfiguration a configuration object appropriate to the file format. * See Document->exportImage for InfoObject details. * @return true if saving succeeded, false if it failed. */ bool save(const QString &filename, double xRes, double yRes, const InfoObject &exportConfiguration); /** * @brief mergeDown merges the given node with the first visible node underneath this node in the layerstack. * This will drop all per-layer metadata. */ Node *mergeDown(); /** * @brief scaleNode - * @param width - * @param height + * @param origin the origin point + * @param width the width + * @param height the height * @param strategy the scaling strategy. There's several ones amongst these that aren't available in the regular UI. *
    *
  • Hermite
  • *
  • Bicubic - Adds pixels using the color of surrounding pixels. Produces smoother tonal gradations than Bilinear.
  • *
  • Box - Replicate pixels in the image. Preserves all the original detail, but can produce jagged effects.
  • *
  • Bilinear - Adds pixels averaging the color values of surrounding pixels. Produces medium quality results when the image is scaled from half to two times the original size.
  • *
  • Bell
  • *
  • BSpline
  • *
  • Lanczos3 - Offers similar results than Bicubic, but maybe a little bit sharper. Can produce light and dark halos along strong edges.
  • *
  • Mitchell
  • *
*/ void scaleNode(QPointF origin, int width, int height, QString strategy); /** * @brief rotateNode rotate this layer by the given radians. * @param radians amount the layer should be rotated in, in radians. */ void rotateNode(double radians); /** * @brief cropNode crop this layer. * @param x the left edge of the cropping rectangle. * @param y the top edge of the cropping rectangle * @param w the right edge of the cropping rectangle * @param h the bottom edge of the cropping rectangle */ void cropNode(int x, int y, int w, int h); /** * @brief shearNode perform a shear operation on this node. * @param angleX the X-angle in degrees to shear by * @param angleY the Y-angle in degrees to shear by */ void shearNode(double angleX, double angleY); /** * @brief thumbnail create a thumbnail of the given dimensions. The thumbnail is sized according * to the layer dimensions, not the image dimensions. If the requested size is too big a null * QImage is created. If the current node cannot generate a thumbnail, a transparent QImage of the * requested size is generated. * @return a QImage representing the layer contents. */ QImage thumbnail(int w, int h); private: friend class Filter; friend class Document; friend class Selection; friend class GroupLayer; friend class FileLayer; friend class FilterLayer; friend class FillLayer; friend class VectorLayer; friend class FilterMask; friend class SelectionMask; /** * @brief paintDevice gives access to the internal paint device of this Node * @return the paintdevice or 0 if the node does not have an editable paint device. */ KisPaintDeviceSP paintDevice() const; KisImageSP image() const; KisNodeSP node() const; struct Private; Private *const d; }; #endif // LIBKIS_NODE_H diff --git a/libs/libkis/Palette.h b/libs/libkis/Palette.h index 813a677ff3..19124eb612 100644 --- a/libs/libkis/Palette.h +++ b/libs/libkis/Palette.h @@ -1,180 +1,180 @@ /* * Copyright (c) 2017 Wolthera van Hövell tot Westerflier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 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 Lesser 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 LIBKIS_PALETTE_H #define LIBKIS_PALETTE_H #include #include #include "kritalibkis_export.h" #include "libkis.h" #include "Resource.h" #include "KoColorSet.h" #include class ManagedColor; /** * @brief The Palette class * Palette is a resource object that stores organised color data. * It's purpose is to allow artists to save colors and store them. * * An example for printing all the palettes and the entries: * * @code import sys from krita import * resources = Application.resources("palette") for (k, v) in resources.items(): print(k) palette = Palette(v) for x in range(palette.numberOfEntries()): entry = palette.colorSetEntryByIndex(x) c = palette.colorForEntry(entry); print(x, entry.name(), entry.id(), entry.spotColor(), c.toQString()) * @endcode */ class KRITALIBKIS_EXPORT Palette : public QObject { public: Palette(Resource *resource); ~Palette() override; /** * @brief numberOfEntries * @return */ int numberOfEntries() const; /** * @brief columnCount * @return the amount of columns this palette is set to use. */ int columnCount(); /** * @brief setColumnCount * Set the amount of columns this palette should use. */ void setColumnCount(int columns); /** * @brief comment * @return the comment or description associated with the palette. */ QString comment(); /** * @brief setComment * set the comment or description associated with the palette. * @param comment */ void setComment(QString comment); /** * @brief groupNames * @return the list of group names. This is list is in the order these groups are in the file. */ QStringList groupNames() const; /** * @brief addGroup * @param name of the new group * @return whether adding the group was successful. */ bool addGroup(QString name); /** * @brief removeGroup * @param name the name of the group to remove. * @param keepColors whether or not to delete all the colors inside, or to move them to the default group. * @return */ bool removeGroup(QString name, bool keepColors = true); /** * @brief colorsCountTotal * @return the total amount of entries in the whole group */ int colorsCountTotal(); /** * @brief colorSetEntryByIndex * get the colorsetEntry from the global index. * @param index the global index * @return the colorset entry */ Swatch *colorSetEntryByIndex(int index); /** * @brief colorSetEntryFromGroup * @param index index in the group. * @param groupName the name of the group to get the color from. * @return the colorsetentry. */ Swatch *colorSetEntryFromGroup(int index, const QString &groupName); /** * @brief addEntry * add an entry to a group. Gets appended to the end. * @param entry the entry * @param groupName the name of the group to add to. */ void addEntry(Swatch entry, QString groupName = QString()); /** * @brief removeEntry - * remove the entry at @param index from the group @param groupName. + * remove the entry at @p index from the group @p groupName. */ void removeEntry(int index, const QString &groupName); /** * @brief changeGroupName * change the group name. * @param oldGroupName the old groupname to change. * @param newGroupName the new name to change it into. * @return whether successful. Reasons for failure include not knowing have oldGroupName */ bool changeGroupName(QString oldGroupName, QString newGroupName); /** * @brief moveGroup * move the group to before groupNameInsertBefore. * @param groupName group to move. * @param groupNameInsertBefore group to inset before. * @return whether successful. Reasons for failure include either group not existing. */ bool moveGroup(const QString &groupName, const QString &groupNameInsertBefore = QString()); /** * @brief save * save the palette * @return whether it was successful. */ bool save(); private: friend class PaletteView; struct Private; Private *const d; /** * @brief colorSet * @return gives qa KoColorSet object back */ KoColorSetSP colorSet(); }; #endif // LIBKIS_PALETTE_H diff --git a/libs/libkis/PaletteView.h b/libs/libkis/PaletteView.h index f9ee621fd3..968e209186 100644 --- a/libs/libkis/PaletteView.h +++ b/libs/libkis/PaletteView.h @@ -1,110 +1,111 @@ /* * Copyright (c) 2017 Wolthera van Hövell tot Westerflier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 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 Lesser 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 LIBKIS_PALETTE_VIEW_H #define LIBKIS_PALETTE_VIEW_H #include #include #include "kritalibkis_export.h" #include "libkis.h" #include "Palette.h" #include "ManagedColor.h" #include "KoColorSet.h" #include #include #include class KisSwatch; /** + * @class PaletteView * @brief The PaletteView class is a wrapper around a MVC method for handling * palettes. This class shows a nice widget that can drag and drop, edit colors in a colorset * and will handle adding and removing entries if you'd like it to. */ class KRITALIBKIS_EXPORT PaletteView : public QWidget { Q_OBJECT public: PaletteView(QWidget *parent = 0); ~PaletteView(); public Q_SLOTS: /** * @brief setPalette * Set a new palette. * @param palette */ void setPalette(Palette *palette); /** * @brief addEntryWithDialog * This gives a simple dialog for adding colors, with options like * adding name, id, and to which group the color should be added. * @param color the default color to add * @return whether it was successful. */ bool addEntryWithDialog(ManagedColor *color); /** * @brief addGroupWithDialog * gives a little dialog to ask for the desired groupname. * @return whether this was successful. */ bool addGroupWithDialog(); /** * @brief removeSelectedEntryWithDialog * removes the selected entry. If it is a group, it pop up a dialog * asking whether the colors should also be removed. * @return whether this was successful */ bool removeSelectedEntryWithDialog(); /** * @brief trySelectClosestColor * tries to select the closest color to the one given. * It does not force a change on the active color. * @param color the color to compare to. */ void trySelectClosestColor(ManagedColor *color); Q_SIGNALS: /** * @brief entrySelectedForeGround * fires when a swatch is selected with leftclick. * @param entry */ void entrySelectedForeGround(Swatch entry); /** * @brief entrySelectedBackGround * fires when a swatch is selected with rightclick. * @param entry */ void entrySelectedBackGround(Swatch entry); private Q_SLOTS: void fgSelected(KisSwatch swatch); void bgSelected(KisSwatch swatch); private: struct Private; const QScopedPointer d; }; #endif // LIBKIS_PALETTE_VIEW_H diff --git a/libs/libkis/Window.h b/libs/libkis/Window.h index b0b0bebf58..aab7b5d2a8 100644 --- a/libs/libkis/Window.h +++ b/libs/libkis/Window.h @@ -1,110 +1,110 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 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 Lesser 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 LIBKIS_WINDOW_H #define LIBKIS_WINDOW_H #include #include #include #include "kritalibkis_export.h" #include "libkis.h" #include /** * Window represents one Krita mainwindow. A window can have any number * of views open on any number of documents. */ class KRITALIBKIS_EXPORT Window : public QObject { Q_OBJECT public: explicit Window(KisMainWindow *window, QObject *parent = 0); ~Window() override; bool operator==(const Window &other) const; bool operator!=(const Window &other) const; public Q_SLOTS: /** * Return a handle to the QMainWindow widget. This is useful * to e.g. parent dialog boxes and message box. */ QMainWindow *qwindow() const; /** * @return a list of open views in this window */ QList views() const; /** * Open a new view on the given document in this window */ View *addView(Document *document); /** * Make the given view active in this window. If the view * does not belong to this window, nothing happens. */ void showView(View *view); /** * @return the currently active view or 0 if no view is active */ View *activeView() const; /** * @brief activate activates this Window. */ void activate(); /** * @brief close the active window and all its Views. If there * are no Views left for a given Document, that Document will * also be closed. */ void close(); /** * @brief createAction creates a QAction object and adds it to the action * manager for this Window. * @param id The unique id for the action. This will be used to * propertize the action if any .action file is present * @param text The user-visible text of the action. If empty, the text from the * .action file is used. - * @param menu a /-separated string that describes which menu the action should + * @param menuLocation a /-separated string that describes which menu the action should * be places in. Default is "tools/scripts" * @return the new action. */ QAction *createAction(const QString &id, const QString &text = QString(), const QString &menuLocation = QString("tools/scripts")); Q_SIGNALS: /// Emitted when the window is closed. void windowClosed(); private: struct Private; Private *const d; }; #endif // LIBKIS_WINDOW_H diff --git a/libs/odf/KoElementReference.h b/libs/odf/KoElementReference.h index 613a925db7..750c3406cf 100644 --- a/libs/odf/KoElementReference.h +++ b/libs/odf/KoElementReference.h @@ -1,131 +1,131 @@ /* * Copyright (c) 2011-2012 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOELEMENTREFERENCE_H #define KOELEMENTREFERENCE_H #include #include #include #include "KoXmlReaderForward.h" #include "kritaodf_export.h" class KoXmlWriter; class KoElementReferenceData : public QSharedData { public: KoElementReferenceData() { xmlid = QUuid::createUuid().toString(); xmlid.remove('{'); xmlid.remove('}'); } KoElementReferenceData(const KoElementReferenceData &other) : QSharedData(other) , xmlid(other.xmlid) { } ~KoElementReferenceData() {} QString xmlid; }; /** * KoElementReference is used to store unique identifiers for elements in an odf document. * Element references are saved as xml:id and optionally for compatibility also as draw:id * and text:id. * * You can use element references wherever you would have used a QString to refer to the id * of an object. * * Element references are implicitly shared, so you can and should pass them along by value. */ class KRITAODF_EXPORT KoElementReference { public: enum GenerationOption { UUID = 0, Counter = 1 }; enum SaveOption { XmlId = 0x0, DrawId = 0x1, TextId = 0x2 }; Q_DECLARE_FLAGS(SaveOptions, SaveOption) KoElementReference(); explicit KoElementReference(const QString &prefix); KoElementReference(const QString &prefix, int counter); KoElementReference(const KoElementReference &other); KoElementReference &operator=(const KoElementReference &rhs); bool operator==(const KoElementReference &other) const; bool operator!=(const KoElementReference &other) const; /** * @return true if the xmlid is valid, i.e., not null */ bool isValid() const; /** * @brief loadOdf creates a new KoElementReference from the given element. If the element * does not have an xml:id, draw:id or text:id attribute, and invalid element reference * is returned. * @param element the element that may contain xml:id, text:id or draw:id. xml:id has * priority. * @return a new element reference */ KoElementReference loadOdf(const KoXmlElement &element); /** * @brief saveOdf saves this element reference into the currently open element in the xml writer. * @param writer the writer we save to - * @param saveOptions determines which attributes we save. We always save the xml:id. + * @param saveOption determines which attributes we save. We always save the xml:id. */ void saveOdf(KoXmlWriter *writer, SaveOption saveOption = XmlId) const; /** * @brief toString creates a QString from the element reference * @return a string that represents the element. Can be used in maps etc. */ QString toString() const; /** * Invalidate the reference */ void invalidate(); private: QSharedDataPointer d; }; Q_DECLARE_OPERATORS_FOR_FLAGS(KoElementReference::SaveOptions) #endif // KOELEMENTREFERENCE_H diff --git a/libs/pigment/KoChannelInfo.h b/libs/pigment/KoChannelInfo.h index 8c3a80d359..d56723f380 100644 --- a/libs/pigment/KoChannelInfo.h +++ b/libs/pigment/KoChannelInfo.h @@ -1,276 +1,277 @@ /* * Copyright (c) 2004 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOCHANNELINFO_H_ #define KOCHANNELINFO_H_ #include #include #include #include /** * This class gives some basic information about a channel, * that is, one of the components that makes up a particular * pixel. */ class KoChannelInfo { public: /** * Used to represent a min and max range. */ struct DoubleRange { public: double minVal, maxVal; public: /// creates an invalid range of 0,0 DoubleRange(void) : minVal(0), maxVal(0) { } /// creates DoubleRange(qreal _minVal, qreal _maxVal) : minVal(_minVal), maxVal(_maxVal) { Q_ASSERT(minVal <= maxVal); } /// true if this range is usable bool isValid(void) const { return minVal < maxVal; } }; public: /// enum to define the type of the channel enum enumChannelType { COLOR, ///< The channel represents a color ALPHA ///< The channel represents the opacity of a pixel //SUBSTANCE, ///< The channel represents a real-world substance like pigments or medium //SUBSTRATE ///< The channel represents a real-world painting substrate like a canvas }; /// enum to define the value of the channel enum enumChannelValueType { UINT8, ///< use this for an unsigned integer 8bits channel UINT16, ///< use this for an integer 16bits channel UINT32, ///< use this for an unsigned integer 21bits channel FLOAT16, ///< use this for a float 16bits channel FLOAT32, ///< use this for a float 32bits channel FLOAT64, ///< use this for a float 64bits channel INT8, ///< use this for an integer 8bits channel INT16, ///< use this for an integer 16bits channel OTHER ///< Use this if the channel is neither an integer or a float }; public: KoChannelInfo() { } /** * @param name of the channel * @param npos position of the channel in the pixel (in bytes) * @param displayPosition the position of the channel in the user-visible order * @param channelType type of the channel * @param channelValueType type of the numerical data used by the channel * @param size number of bytes (not bits) of the channel (if -1, it is deduced from the channelType) * @param color a color to represent that channel (for instance in an histogram) + * @param uiMinMax the UI range */ KoChannelInfo(const QString & name, qint32 npos, qint32 displayPosition, enumChannelType channelType, enumChannelValueType channelValueType, qint32 size = -1, const QColor &color = QColor(0, 0, 0), const DoubleRange &uiMinMax = DoubleRange()) : m_name(name) , m_pos(npos) , m_displayPosition(displayPosition) , m_channelType(channelType) , m_channelValueType(channelValueType) , m_size(size) , m_color(color) , m_uiMinMax(uiMinMax) { switch(m_channelValueType) { case UINT8: case INT8: Q_ASSERT(m_size == -1 || m_size == 1); m_size = 1; break; case UINT16: case INT16: Q_ASSERT(m_size == -1 || m_size == 2); m_size = 2; break; case UINT32: Q_ASSERT(m_size == -1 || m_size == 4); m_size = 4; break; case FLOAT16: Q_ASSERT(m_size == -1 || m_size == 2); m_size = 2; break; case FLOAT32: Q_ASSERT(m_size == -1 || m_size == 4); m_size = 4; break; case FLOAT64: Q_ASSERT(m_size == -1 || m_size == 8); m_size = 8; break; case OTHER: Q_ASSERT(m_size != -1); } if (!uiMinMax.isValid()) { switch (m_channelValueType) { case UINT8: m_uiMinMax.minVal = std::numeric_limits::min(); m_uiMinMax.maxVal = std::numeric_limits::max(); break; case INT8: m_uiMinMax.minVal = std::numeric_limits::min(); m_uiMinMax.maxVal = std::numeric_limits::max(); break; case UINT16: m_uiMinMax.minVal = std::numeric_limits::min(); m_uiMinMax.maxVal = std::numeric_limits::max(); break; case INT16: m_uiMinMax.minVal = std::numeric_limits::min(); m_uiMinMax.maxVal = std::numeric_limits::max(); break; case UINT32: m_uiMinMax.minVal = std::numeric_limits::min(); m_uiMinMax.maxVal = std::numeric_limits::max(); break; default: // assume real otherwise, which is 0..1 by default m_uiMinMax.minVal = 0.0; m_uiMinMax.maxVal = 1.0; break; } } Q_ASSERT(m_uiMinMax.isValid()); } public: /** * converts the display position to the pixel-order index in the channels vector. */ static int displayPositionToChannelIndex(int displayPosition, const QList &channels) { for (int i = 0; i < channels.size(); ++i) { if (channels.at(i)->displayPosition() == displayPosition) { return i; } } return -1; } static QList displayOrderSorted(const QList &channels) { QList sortedChannels; for (int i = 0; i < channels.size(); ++i) { Q_FOREACH (KoChannelInfo* channel, channels) { if (channel->displayPosition() == i) { sortedChannels << channel; break; } } } Q_ASSERT(channels.size() == sortedChannels.size()); return sortedChannels; } /** * User-friendly name for this channel for presentation purposes in the gui */ inline QString name() const { return m_name; } /** * @return the position of the first byte of the channel in the pixel */ inline qint32 pos() const { return m_pos; } /** * @return the displayPosition of the channel in the pixel */ inline qint32 displayPosition() const { return m_displayPosition; } /** * @return the number of bytes this channel takes */ inline qint32 size() const { return m_size; } /** * @return the type of the channel */ inline enumChannelType channelType() const { return m_channelType; } /** * @return the type of the value of the channel (float, uint8 or uint16) */ inline enumChannelValueType channelValueType() const { return m_channelValueType; } /** * This is a color that can be used to represent this channel in histograms and so. * By default this is black, so keep in mind that many channels might look the same */ inline QColor color() const { return m_color; } /** * A channel is less than another channel if its pos is smaller. */ inline bool operator<(const KoChannelInfo & info) { return m_pos < info.m_pos; } /** * Gets the minimum value that this channel should have. * This is suitable for UI use. */ inline double getUIMin(void) const { return m_uiMinMax.minVal; } /** * Gets the minimum value that this channel should have. * This is suitable for UI use. */ inline double getUIMax(void) const { return m_uiMinMax.maxVal; } private: QString m_name; qint32 m_pos; qint32 m_displayPosition; enumChannelType m_channelType; enumChannelValueType m_channelValueType; qint32 m_size; QColor m_color; DoubleRange m_uiMinMax; }; #endif // KOCHANNELINFO_H_ diff --git a/libs/pigment/KoColor.h b/libs/pigment/KoColor.h index 8db9b2aa88..eed5a90663 100644 --- a/libs/pigment/KoColor.h +++ b/libs/pigment/KoColor.h @@ -1,276 +1,276 @@ /* * Copyright (c) 2005 Boudewijn Rempt * Copyright (C) 2007 Thomas Zander * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOCOLOR_H #define KOCOLOR_H #include #include #include #include "kritapigment_export.h" #include "KoColorConversionTransformation.h" #include "KoColorSpaceRegistry.h" #include "KoColorSpaceTraits.h" #include class QDomDocument; class QDomElement; class KoColorProfile; class KoColorSpace; /** * A KoColor describes a color in a certain colorspace. The color is stored in a buffer * that can be manipulated by the function of the color space. */ class KRITAPIGMENT_EXPORT KoColor : public boost::equality_comparable { public: /// Create an empty KoColor. It will be valid, but also black and transparent KoColor(); /// Create a null KoColor. It will be valid, but all channels will be set to 0 explicit KoColor(const KoColorSpace * colorSpace); /// Create a KoColor from a QColor. The QColor is immediately converted to native. The QColor /// is assumed to have the current monitor profile. KoColor(const QColor & color, const KoColorSpace * colorSpace); /// Create a KoColor using a native color strategy. The data is copied. KoColor(const quint8 * data, const KoColorSpace * colorSpace); /// Create a KoColor by converting src into another colorspace KoColor(const KoColor &src, const KoColorSpace * colorSpace); /// Copy constructor -- deep copies the colors. KoColor(const KoColor & rhs) { *this = rhs; } /** * assignment operator to copy the data from the param color into this one. - * @param other the color we are going to copy + * @param rhs the color we are going to copy * @return this color */ inline KoColor &operator=(const KoColor &rhs) { if (&rhs == this) { return *this; } m_colorSpace = rhs.m_colorSpace; m_size = rhs.m_size; memcpy(m_data, rhs.m_data, m_size); assertPermanentColorspace(); return *this; } bool operator==(const KoColor &other) const { if (*colorSpace() != *other.colorSpace()) { return false; } if (m_size != other.m_size) { return false; } return memcmp(m_data, other.m_data, m_size) == 0; } /// return the current colorSpace const KoColorSpace * colorSpace() const { return m_colorSpace; } /// return the current profile const KoColorProfile *profile() const; /// Convert this KoColor to the specified colorspace. If the specified colorspace is the /// same as the original colorspace, do nothing void convertTo(const KoColorSpace * cs, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags); void convertTo(const KoColorSpace * cs); /// Copies this color and converts it to the specified colorspace. If the specified colorspace is the /// same as the original colorspace, just returns a copy KoColor convertedTo(const KoColorSpace * cs, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const; /// Copies this color and converts it to the specified colorspace. If the specified colorspace is the /// same as the original colorspace, just returns a copy KoColor convertedTo(const KoColorSpace * cs) const; /// assign new profile without converting pixel data void setProfile(const KoColorProfile *profile); /// Replace the existing color data, and colorspace with the specified data. /// The data is copied. void setColor(const quint8 * data, const KoColorSpace * colorSpace = 0); /// Convert the color from src and replace the value of the current color with the converted data. /// Don't convert the color if src and this have the same colorspace. void fromKoColor(const KoColor& src); /// a convenience method for the above. void toQColor(QColor *c) const; /// a convenience method for the above. QColor toQColor() const; /** * Convenient function to set the opacity of the color. */ void setOpacity(quint8 alpha); void setOpacity(qreal alpha); /** * Convenient function that return the opacity of the color */ quint8 opacityU8() const; qreal opacityF() const; /// Convenient function for converting from a QColor void fromQColor(const QColor& c); /** * @return the buffer associated with this color object to be used with the * transformation object created by the color space of this KoColor * or to copy to a different buffer from the same color space */ quint8 * data() { return m_data; } /** * @return the buffer associated with this color object to be used with the * transformation object created by the color space of this KoColor * or to copy to a different buffer from the same color space */ const quint8 * data() const { return m_data; } /** * Channelwise subtracts \p value from *this and stores the result in *this * * Throws a safe assert if the colorspaces of the two colors are different */ void subtract(const KoColor &value); /** * Channelwise subtracts \p value from a copy of *this and returns the result * * Throws a safe assert if the colorspaces of the two colors are different */ KoColor subtracted(const KoColor &value) const; /** * Channelwise adds \p value to *this and stores the result in *this * * Throws a safe assert if the colorspaces of the two colors are different */ void add(const KoColor &value); /** * Channelwise adds \p value to a copy of *this and returns the result * * Throws a safe assert if the colorspaces of the two colors are different */ KoColor added(const KoColor &value) const; /** * Serialize this color following Create's swatch color specification available * at http://create.freedesktop.org/wiki/index.php/Swatches_-_colour_file_format * - * This function doesn't create the element but rather the , - * , ... elements. It is assumed that colorElt is the + * This function doesn't create the \ element but rather the \, + * \, \ ... elements. It is assumed that colorElt is the \ * element. * * @param colorElt root element for the serialization, it is assumed that this - * element is + * element is \ * @param doc is the document containing colorElt */ void toXML(QDomDocument& doc, QDomElement& colorElt) const; /** * Unserialize a color following Create's swatch color specification available * at http://create.freedesktop.org/wiki/index.php/Swatches_-_colour_file_format * - * @param elt the element to unserialize (, , ) + * @param elt the element to unserialize (\, \, \) * @param bitDepthId the bit depth is unspecified by the spec, this allow to select * a preferred bit depth for creating the KoColor object (if that * bit depth isn't available, this function will randomly select * an other bit depth) * @return the unserialize color, or an empty color object if the function failed * to unserialize the color */ static KoColor fromXML(const QDomElement& elt, const QString & bitDepthId); /** * Unserialize a color following Create's swatch color specification available * at http://create.freedesktop.org/wiki/index.php/Swatches_-_colour_file_format * - * @param elt the element to unserialize (, , ) + * @param elt the element to unserialize (\, \, \) * @param bitDepthId the bit depth is unspecified by the spec, this allow to select * a preferred bit depth for creating the KoColor object (if that * bit depth isn't available, this function will randomly select * an other bit depth) * @param ok If a an error occurs, *ok is set to false; otherwise it's set to true * @return the unserialize color, or an empty color object if the function failed * to unserialize the color */ static KoColor fromXML(const QDomElement& elt, const QString & bitDepthId, bool* ok); /** * @brief toQString create a user-visible string of the channel names and the channel values * @param color the color to create the string from * @return a string that can be used to display the values of this color to the user. */ static QString toQString(const KoColor &color); #ifndef NODEBUG /// use qDebug calls to print internal info void dump() const; #endif private: inline void assertPermanentColorspace() { #ifndef NODEBUG if (m_colorSpace) { Q_ASSERT(*m_colorSpace == *KoColorSpaceRegistry::instance()->permanentColorspace(m_colorSpace)); } #endif } const KoColorSpace *m_colorSpace; quint8 m_data[MAX_PIXEL_SIZE]; quint8 m_size; }; Q_DECLARE_METATYPE(KoColor) KRITAPIGMENT_EXPORT QDebug operator<<(QDebug dbg, const KoColor &color); #endif diff --git a/libs/pigment/KoColorConversionCache.h b/libs/pigment/KoColorConversionCache.h index cc8d9c6f55..d47895d58a 100644 --- a/libs/pigment/KoColorConversionCache.h +++ b/libs/pigment/KoColorConversionCache.h @@ -1,88 +1,90 @@ /* * Copyright (C) 2007 Cyrille Berger * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _KO_COLOR_CONVERSION_CACHE_HPP_ #define _KO_COLOR_CONVERSION_CACHE_HPP_ class KoCachedColorConversionTransformation; class KoColorSpace; #include "KoColorConversionTransformation.h" /** * This class holds a cache of KoColorConversionTransformations. * * This class is not part of public API, and can be changed without notice. */ class KoColorConversionCache { public: struct CachedTransformation; public: KoColorConversionCache(); ~KoColorConversionCache(); /** * This function returns a cached color transformation if available * or create one. * @param src source color space * @param dst destination color space + * @param _renderingIntent rendering intent + * @param conversionFlags conversion flags */ KoCachedColorConversionTransformation cachedConverter(const KoColorSpace* src, const KoColorSpace* dst, KoColorConversionTransformation::Intent _renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags); /** * This function is called by the destructor of the color space to * warn the cache that any pointers to this color space is going to * be invalid and that the cache needs to stop using those pointers. * @param src source color space */ void colorSpaceIsDestroyed(const KoColorSpace* src); private: struct Private; Private* const d; }; /** * This class hold a cached color conversion. It can only be created * by the cache and when it's deleted it return the transformation to * the pool of available color conversion transformation. * * This class is not part of public API, and can be changed without notice. */ class KoCachedColorConversionTransformation { friend class KoColorConversionCache; private: KoCachedColorConversionTransformation(KoColorConversionCache* cache, KoColorConversionCache::CachedTransformation* transfo); public: KoCachedColorConversionTransformation(const KoCachedColorConversionTransformation&); ~KoCachedColorConversionTransformation(); public: const KoColorConversionTransformation* transformation() const; private: struct Private; Private* const d; }; #endif diff --git a/libs/pigment/KoColorConversionTransformationAbstractFactory.h b/libs/pigment/KoColorConversionTransformationAbstractFactory.h index 449648e05f..585147bef6 100644 --- a/libs/pigment/KoColorConversionTransformationAbstractFactory.h +++ b/libs/pigment/KoColorConversionTransformationAbstractFactory.h @@ -1,68 +1,70 @@ /* * Copyright (c) 2008 Cyrille Berger * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _KO_COLOR_CONVERSION_TRANSFORMATION_ABSTRACT_FACTORY_H_ #define _KO_COLOR_CONVERSION_TRANSFORMATION_ABSTRACT_FACTORY_H_ #include "kritapigment_export.h" #include #include class KRITAPIGMENT_EXPORT KoColorConversionTransformationAbstractFactory { public: KoColorConversionTransformationAbstractFactory() {} virtual ~KoColorConversionTransformationAbstractFactory() {} /** * Creates a color transformation between the source color space and the destination * color space. * * @param srcColorSpace source color space * @param dstColorSpace destination color space + * @param renderingIntent rendering intent + * @param conversionFlags conversion flags */ virtual KoColorConversionTransformation* createColorTransformation(const KoColorSpace* srcColorSpace, const KoColorSpace* dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const = 0; virtual KoColorProofingConversionTransformation* createColorProofingTransformation(const KoColorSpace* srcColorSpace, const KoColorSpace* dstColorSpace, const KoColorSpace* proofingSpace, KoColorProofingConversionTransformation::Intent renderingIntent, KoColorProofingConversionTransformation::Intent proofingIntent, KoColorProofingConversionTransformation::ConversionFlags conversionFlags, quint8 *gamutWarning, double adaptationState) const { Q_UNUSED(srcColorSpace); Q_UNUSED(dstColorSpace); Q_UNUSED(proofingSpace); Q_UNUSED(renderingIntent); Q_UNUSED(proofingIntent); Q_UNUSED(conversionFlags); Q_UNUSED(gamutWarning); Q_UNUSED(adaptationState); qFatal("createColorProofinTransform undefined."); return 0; } }; #endif diff --git a/libs/pigment/KoColorSpace.h b/libs/pigment/KoColorSpace.h index 67fa12d938..fc0d6a5032 100644 --- a/libs/pigment/KoColorSpace.h +++ b/libs/pigment/KoColorSpace.h @@ -1,644 +1,641 @@ /* * Copyright (c) 2005 Boudewijn Rempt * Copyright (c) 2006-2007 Cyrille Berger * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOCOLORSPACE_H #define KOCOLORSPACE_H #include #include #include #include #include #include #include "KoColorSpaceConstants.h" #include "KoColorConversionTransformation.h" #include "KoColorProofingConversionTransformation.h" #include "KoCompositeOp.h" #include #include "kritapigment_export.h" class QDomDocument; class QDomElement; class KoChannelInfo; class KoColorProfile; class KoColorTransformation; class QBitArray; enum Deletability { OwnedByRegistryDoNotDelete, OwnedByRegistryRegistryDeletes, NotOwnedByRegistry }; enum ColorSpaceIndependence { FULLY_INDEPENDENT, TO_LAB16, TO_RGBA8, TO_RGBA16 }; class KoMixColorsOp; class KoConvolutionOp; /** * A KoColorSpace is the definition of a certain color space. * * A color model and a color space are two related concepts. A color * model is more general in that it describes the channels involved and * how they in broad terms combine to describe a color. Examples are * RGB, HSV, CMYK. * * A color space is more specific in that it also describes exactly how * the channels are combined. So for each color model there can be a * number of specific color spaces. So RGB is the model and sRGB, * adobeRGB, etc are colorspaces. * * In Pigment KoColorSpace acts as both a color model and a color space. * You can think of the class definition as the color model, but the * instance of the class as representing a colorspace. * * A third concept is the profile represented by KoColorProfile. It * represents the info needed to specialize a color model into a color * space. * * KoColorSpace is an abstract class serving as an interface. * * Subclasses implement actual color spaces * Some subclasses implement only some parts and are named Traits * */ class KRITAPIGMENT_EXPORT KoColorSpace : public boost::equality_comparable { friend class KoColorSpaceRegistry; friend class KoColorSpaceFactory; protected: /// Only for use by classes that serve as baseclass for real color spaces KoColorSpace(); public: /// Should be called by real color spaces KoColorSpace(const QString &id, const QString &name, KoMixColorsOp* mixColorsOp, KoConvolutionOp* convolutionOp); virtual bool operator==(const KoColorSpace& rhs) const; protected: virtual ~KoColorSpace(); public: //========== Gamut and other basic info ===================================// /* * @returns QPolygonF with 5*channel samples converted to xyY. * maybe convert to 3d space in future? */ QPolygonF gamutXYY() const; /* * @returns a polygon with 5 samples per channel converted to xyY, but unlike * gamutxyY it focuses on the luminance. This then can be used to visualise * the approximate trc of a given colorspace. */ QPolygonF estimatedTRCXYY() const; QVector lumaCoefficients() const; //========== Channels =====================================================// /// Return a list describing all the channels this color model has. The order /// of the channels in the list is the order of channels in the pixel. To find /// out the preferred display position, use KoChannelInfo::displayPosition. QList channels() const; /** * The total number of channels for a single pixel in this color model */ virtual quint32 channelCount() const = 0; /** * The total number of color channels (excludes alpha) for a single * pixel in this color model. */ virtual quint32 colorChannelCount() const = 0; /** * returns a QBitArray that contains true for the specified * channel types: * * @param color if true, set all color channels to true * @param alpha if true, set all alpha channels to true * * The order of channels is the colorspace descriptive order, * not the pixel order. */ QBitArray channelFlags(bool color = true, bool alpha = false) const; /** * The size in bytes of a single pixel in this color model */ virtual quint32 pixelSize() const = 0; /** * Return a string with the channel's value suitable for display in the gui. */ virtual QString channelValueText(const quint8 *pixel, quint32 channelIndex) const = 0; /** * Return a string with the channel's value with integer * channels normalised to the floating point range 0 to 1, if * appropriate. */ virtual QString normalisedChannelValueText(const quint8 *pixel, quint32 channelIndex) const = 0; /** * Return a QVector of floats with channels' values normalized * to floating point range 0 to 1. */ virtual void normalisedChannelsValue(const quint8 *pixel, QVector &channels) const = 0; /** * Write in the pixel the value from the normalized vector. */ virtual void fromNormalisedChannelsValue(quint8 *pixel, const QVector &values) const = 0; /** * Convert the value of the channel at the specified position into * an 8-bit value. The position is not the number of bytes, but * the position of the channel as defined in the channel info list. */ virtual quint8 scaleToU8(const quint8 * srcPixel, qint32 channelPos) const = 0; /** * Set dstPixel to the pixel containing only the given channel of srcPixel. The remaining channels * should be set to whatever makes sense for 'empty' channels of this color space, * with the intent being that the pixel should look like it only has the given channel. */ virtual void singleChannelPixel(quint8 *dstPixel, const quint8 *srcPixel, quint32 channelIndex) const = 0; //========== Identification ===============================================// /** * ID for use in files and internally: unchanging name. As the id must be unique * it is usually the concatenation of the id of the color model and of the color * depth, for instance "RGBA8" or "CMYKA16" or "XYZA32f". */ QString id() const; /** * User visible name which contains the name of the color model and of the color depth. * For instance "RGBA (8-bits)" or "CMYKA (16-bits)". */ QString name() const; /** * @return a string that identify the color model (for instance "RGB" or "CMYK" ...) * @see KoColorModelStandardIds.h */ virtual KoID colorModelId() const = 0; /** * @return a string that identify the bit depth (for instance "U8" or "F16" ...) * @see KoColorModelStandardIds.h */ virtual KoID colorDepthId() const = 0; /** * @return true if the profile given in argument can be used by this color space */ virtual bool profileIsCompatible(const KoColorProfile* profile) const = 0; /** * If false, images in this colorspace will degrade considerably by * functions, tools and filters that have the given measure of colorspace * independence. * * @param independence the measure to which this colorspace will suffer * from the manipulations of the tool or filter asking * @return false if no degradation will take place, true if degradation will * take place */ virtual bool willDegrade(ColorSpaceIndependence independence) const = 0; //========== Capabilities =================================================// /** * Tests if the colorspace offers the specific composite op. */ virtual bool hasCompositeOp(const QString & id) const; /** * Returns the list of user-visible composite ops supported by this colorspace. */ virtual QList compositeOps() const; /** * Retrieve a single composite op from the ones this colorspace offers. * If the requeste composite op does not exist, COMPOSITE_OVER is returned. */ const KoCompositeOp * compositeOp(const QString & id) const; /** * add a composite op to this colorspace. */ virtual void addCompositeOp(const KoCompositeOp * op); /** * Returns true if the colorspace supports channel values outside the * (normalised) range 0 to 1. */ virtual bool hasHighDynamicRange() const = 0; //========== Display profiles =============================================// /** * Return the profile of this color space. */ virtual const KoColorProfile * profile() const = 0; //================= Conversion functions ==================================// /** * The fromQColor methods take a given color defined as an RGB QColor * and fills a byte array with the corresponding color in the * the colorspace managed by this strategy. * * @param color the QColor that will be used to fill dst * @param dst a pointer to a pixel * @param profile the optional profile that describes the color values of QColor */ virtual void fromQColor(const QColor& color, quint8 *dst, const KoColorProfile * profile = 0) const = 0; /** * The toQColor methods take a byte array that is at least pixelSize() long * and converts the contents to a QColor, using the given profile as a source * profile and the optional profile as a destination profile. * * @param src a pointer to the source pixel * @param c the QColor that will be filled with the color at src * @param profile the optional profile that describes the color in c, for instance the monitor profile */ virtual void toQColor(const quint8 *src, QColor *c, const KoColorProfile * profile = 0) const = 0; /** * Convert the pixels in data to (8-bit BGRA) QImage using the specified profiles. * * @param data A pointer to a contiguous memory region containing width * height pixels * @param width in pixels * @param height in pixels * @param dstProfile destination profile * @param renderingIntent the rendering intent + * @param conversionFlags conversion flags */ virtual QImage convertToQImage(const quint8 *data, qint32 width, qint32 height, const KoColorProfile * dstProfile, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const; /** * Convert the specified data to Lab (D50). All colorspaces are guaranteed to support this * * @param src the source data * @param dst the destination data * @param nPixels the number of source pixels */ virtual void toLabA16(const quint8 * src, quint8 * dst, quint32 nPixels) const; /** * Convert the specified data from Lab (D50). to this colorspace. All colorspaces are * guaranteed to support this. * * @param src the pixels in 16 bit lab format * @param dst the destination data * @param nPixels the number of pixels in the array */ virtual void fromLabA16(const quint8 * src, quint8 * dst, quint32 nPixels) const; /** * Convert the specified data to sRGB 16 bits. All colorspaces are guaranteed to support this * * @param src the source data * @param dst the destination data * @param nPixels the number of source pixels */ virtual void toRgbA16(const quint8 * src, quint8 * dst, quint32 nPixels) const; /** * Convert the specified data from sRGB 16 bits. to this colorspace. All colorspaces are * guaranteed to support this. * * @param src the pixels in 16 bit rgb format * @param dst the destination data * @param nPixels the number of pixels in the array */ virtual void fromRgbA16(const quint8 * src, quint8 * dst, quint32 nPixels) const; /** * Create a color conversion transformation. */ virtual KoColorConversionTransformation* createColorConverter(const KoColorSpace * dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const; /** * Convert a byte array of srcLen pixels *src to the specified color space * and put the converted bytes into the prepared byte array *dst. * * Returns false if the conversion failed, true if it succeeded * * This function is not thread-safe. If you want to apply multiple conversion * in different threads at the same time, you need to create one color converter * per-thread using createColorConverter. */ virtual bool convertPixelsTo(const quint8 * src, quint8 * dst, const KoColorSpace * dstColorSpace, quint32 numPixels, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const; virtual KoColorConversionTransformation *createProofingTransform(const KoColorSpace * dstColorSpace, const KoColorSpace * proofingSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::Intent proofingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags, quint8 *gamutWarning, double adaptationState) const; /** * @brief proofPixelsTo - * @param src - * @param dst - * @param dstColorSpace the colorspace to which we go to. - * @param proofingSpace the proofing space. + * @param src source + * @param dst destination * @param numPixels the amount of pixels. - * @param renderingIntent the rendering intent used for rendering. - * @param proofingIntent the intent used for proofing. - * @param conversionFlags the conversion flags. - * @param gamutWarning the data() of a KoColor. - * @param adaptationState the state of adaptation, only affects absolute colorimetric. + * @param proofingTransform the intent used for proofing. * @return */ virtual bool proofPixelsTo(const quint8 * src, quint8 * dst, quint32 numPixels, KoColorConversionTransformation *proofingTransform) const; //============================== Manipulation functions ==========================// // // The manipulation functions have default implementations that _convert_ the pixel // to a QColor and back. Reimplement these methods in your color strategy! // /** * Get the alpha value of the given pixel, downscaled to an 8-bit value. */ virtual quint8 opacityU8(const quint8 * pixel) const = 0; virtual qreal opacityF(const quint8 * pixel) const = 0; /** * Set the alpha channel of the given run of pixels to the given value. * * pixels -- a pointer to the pixels that will have their alpha set to this value * alpha -- a downscaled 8-bit value for opacity * nPixels -- the number of pixels * */ virtual void setOpacity(quint8 * pixels, quint8 alpha, qint32 nPixels) const = 0; virtual void setOpacity(quint8 * pixels, qreal alpha, qint32 nPixels) const = 0; /** * Multiply the alpha channel of the given run of pixels by the given value. * * pixels -- a pointer to the pixels that will have their alpha set to this value * alpha -- a downscaled 8-bit value for opacity * nPixels -- the number of pixels * */ virtual void multiplyAlpha(quint8 * pixels, quint8 alpha, qint32 nPixels) const = 0; /** * Applies the specified 8-bit alpha mask to the pixels. We assume that there are just * as many alpha values as pixels but we do not check this; the alpha values * are assumed to be 8-bits. */ virtual void applyAlphaU8Mask(quint8 * pixels, const quint8 * alpha, qint32 nPixels) const = 0; /** * Applies the inverted 8-bit alpha mask to the pixels. We assume that there are just * as many alpha values as pixels but we do not check this; the alpha values * are assumed to be 8-bits. */ virtual void applyInverseAlphaU8Mask(quint8 * pixels, const quint8 * alpha, qint32 nPixels) const = 0; /** * Applies the specified float alpha mask to the pixels. We assume that there are just * as many alpha values as pixels but we do not check this; alpha values have to be between 0.0 and 1.0 */ virtual void applyAlphaNormedFloatMask(quint8 * pixels, const float * alpha, qint32 nPixels) const = 0; /** * Applies the inverted specified float alpha mask to the pixels. We assume that there are just * as many alpha values as pixels but we do not check this; alpha values have to be between 0.0 and 1.0 */ virtual void applyInverseNormedFloatMask(quint8 * pixels, const float * alpha, qint32 nPixels) const = 0; /** * Create an adjustment object for adjusting the brightness and contrast * transferValues is a 256 bins array with values from 0 to 0xFFFF * This function is thread-safe, but you need to create one KoColorTransformation per thread. */ virtual KoColorTransformation *createBrightnessContrastAdjustment(const quint16 *transferValues) const = 0; /** * Create an adjustment object for adjusting individual channels * transferValues is an array of colorChannelCount number of 256 bins array with values from 0 to 0xFFFF * This function is thread-safe, but you need to create one KoColorTransformation per thread. * * The layout of the channels must be the following: * * 0..N-2 - color channels of the pixel; * N-1 - alpha channel of the pixel (if exists) */ virtual KoColorTransformation *createPerChannelAdjustment(const quint16 * const* transferValues) const = 0; /** * Darken all color channels with the given amount. If compensate is true, * the compensation factor will be used to limit the darkening. * */ virtual KoColorTransformation *createDarkenAdjustment(qint32 shade, bool compensate, qreal compensation) const = 0; /** * Invert color channels of the given pixels * This function is thread-safe, but you need to create one KoColorTransformation per thread. */ virtual KoColorTransformation *createInvertTransformation() const = 0; /** * Get the difference between 2 colors, normalized in the range (0,255). Only completely * opaque and completely transparent are taken into account when computing the difference; * other transparency levels are not regarded when finding the difference. */ virtual quint8 difference(const quint8* src1, const quint8* src2) const = 0; /** * Get the difference between 2 colors, normalized in the range (0,255). This function * takes the Alpha channel of the pixel into account. Alpha channel has the same * weight as Lightness channel. */ virtual quint8 differenceA(const quint8* src1, const quint8* src2) const = 0; /** * @return the mix color operation of this colorspace (do not delete it locally, it's deleted by the colorspace). */ virtual KoMixColorsOp* mixColorsOp() const; /** * @return the convolution operation of this colorspace (do not delete it locally, it's deleted by the colorspace). */ virtual KoConvolutionOp* convolutionOp() const; /** * Calculate the intensity of the given pixel, scaled down to the range 0-255. XXX: Maybe this should be more flexible */ virtual quint8 intensity8(const quint8 * src) const = 0; /* *increase luminosity by step */ virtual void increaseLuminosity(quint8 * pixel, qreal step) const; virtual void decreaseLuminosity(quint8 * pixel, qreal step) const; virtual void increaseSaturation(quint8 * pixel, qreal step) const; virtual void decreaseSaturation(quint8 * pixel, qreal step) const; virtual void increaseHue(quint8 * pixel, qreal step) const; virtual void decreaseHue(quint8 * pixel, qreal step) const; virtual void increaseRed(quint8 * pixel, qreal step) const; virtual void increaseGreen(quint8 * pixel, qreal step) const; virtual void increaseBlue(quint8 * pixel, qreal step) const; virtual void increaseYellow(quint8 * pixel, qreal step) const; virtual void toHSY(const QVector &channelValues, qreal *hue, qreal *sat, qreal *luma) const = 0; virtual QVector fromHSY(qreal *hue, qreal *sat, qreal *luma) const = 0; virtual void toYUV(const QVector &channelValues, qreal *y, qreal *u, qreal *v) const = 0; virtual QVector fromYUV(qreal *y, qreal *u, qreal *v) const = 0; /** * Compose two arrays of pixels together. If source and target * are not the same color model, the source pixels will be * converted to the target model. We're "dst" -- "dst" pixels are always in _this_ * colorspace. * * @param srcSpace the colorspace of the source pixels that will be composited onto "us" - * @param param the information needed for blitting e.g. the source and destination pixel data, + * @param params the information needed for blitting e.g. the source and destination pixel data, * the opacity and flow, ... * @param op the composition operator to use, e.g. COPY_OVER + * @param renderingIntent the rendering intent + * @param conversionFlags the conversion flags. * */ virtual void bitBlt(const KoColorSpace* srcSpace, const KoCompositeOp::ParameterInfo& params, const KoCompositeOp* op, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const; /** * Serialize this color following Create's swatch color specification available * at http://create.freedesktop.org/wiki/index.php/Swatches_-_colour_file_format * - * This function doesn't create the element but rather the , - * , ... elements. It is assumed that colorElt is the + * This function doesn't create the \ element but rather the \, + * \, \ ... elements. It is assumed that colorElt is the \ * element. * * @param pixel buffer to serialized * @param colorElt root element for the serialization, it is assumed that this - * element is + * element is \ * @param doc is the document containing colorElt */ virtual void colorToXML(const quint8* pixel, QDomDocument& doc, QDomElement& colorElt) const = 0; /** * Unserialize a color following Create's swatch color specification available * at http://create.freedesktop.org/wiki/index.php/Swatches_-_colour_file_format * * @param pixel buffer where the color will be unserialized - * @param elt the element to unserialize (, , ) + * @param elt the element to unserialize (\, \, \) * @return the unserialize color, or an empty color object if the function failed * to unserialize the color */ virtual void colorFromXML(quint8* pixel, const QDomElement& elt) const = 0; KoColorTransformation* createColorTransformation(const QString & id, const QHash & parameters) const; protected: /** * Use this function in the constructor of your colorspace to add the information about a channel. * @param ci a pointer to the information about a channel */ virtual void addChannel(KoChannelInfo * ci); const KoColorConversionTransformation* toLabA16Converter() const; const KoColorConversionTransformation* fromLabA16Converter() const; const KoColorConversionTransformation* toRgbA16Converter() const; const KoColorConversionTransformation* fromRgbA16Converter() const; /** * Returns the thread-local conversion cache. If it doesn't exist * yet, it is created. If it is currently too small, it is resized. */ QVector * threadLocalConversionCache(quint32 size) const; /** * This function defines the behavior of the bitBlt function * when the composition of pixels in different colorspaces is * requested, that is in case: * * srcCS == any * dstCS == this * * 1) preferCompositionInSourceColorSpace() == false, * * the source pixels are first converted to *this color space * and then composition is performed. * * 2) preferCompositionInSourceColorSpace() == true, * * the destination pixels are first converted into *srcCS color * space, then the composition is done, and the result is finally * converted into *this colorspace. * * This is used by alpha8() color space mostly, because it has * weaker representation of the color, so the composition * should be done in CS with richer functionality. */ virtual bool preferCompositionInSourceColorSpace() const; struct Private; Private * const d; }; inline QDebug operator<<(QDebug dbg, const KoColorSpace *cs) { if (cs) { dbg.nospace() << cs->name() << " (" << cs->colorModelId().id() << "," << cs->colorDepthId().id() << " )"; } else { dbg.nospace() << "0x0"; } return dbg.space(); } #endif // KOCOLORSPACE_H diff --git a/libs/pigment/KoColorSpaceRegistry.h b/libs/pigment/KoColorSpaceRegistry.h index 09d4ce5136..6f5160a975 100644 --- a/libs/pigment/KoColorSpaceRegistry.h +++ b/libs/pigment/KoColorSpaceRegistry.h @@ -1,361 +1,361 @@ /* * Copyright (c) 2003 Patrick Julien * Copyright (c) 2004,2010 Cyrille Berger * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOCOLORSPACEREGISTRY_H #define KOCOLORSPACEREGISTRY_H #include #include #include #include "kritapigment_export.h" #include #include #include +#include class KoColorProfile; class KoColorConversionSystem; class KoColorConversionCache; class KoColorConversionTransformation; /** * The registry for colorspaces and profiles. * This class contains: * - a registry of colorspace instantiated with specific profiles. * - a registry of singleton colorspace factories. * - a registry of icc profiles * * Locking policy details: * * Basically, we have two levels of locks in the registry: * 1) (outer level) is Private::registrylock, which controls the structures * of the color space registry itself * 2) (inner level) is KoColorProfileStorage::Private::lock controls * the structures related to profiles. * * The locks can be taken individually, but if you are going to take both * of them, you should always follow the order 1) registry; 2) profiles. * Otherwise you'll get a deadlock. * * To avoid recursive deadlocks, all the dependent classes * (KoColorConversionSystem and KoColorSpaceFactory) now do not use the direct * links to the registry. Instead, they use special private interfaces that * skip recursive locking and ensure we take a lock twice. */ class KRITAPIGMENT_EXPORT KoColorSpaceRegistry { public: KoColorSpaceRegistry(); enum ColorSpaceListVisibility { OnlyUserVisible = 1, ///< Only user visible color space AllColorSpaces = 4 ///< All color space even those not visible to the user }; enum ColorSpaceListProfilesSelection { OnlyDefaultProfile = 1, ///< Only add the default profile AllProfiles = 4 ///< Add all profiles }; /** * Return an instance of the KoColorSpaceRegistry * Creates an instance if that has never happened before and returns the singleton instance. */ static KoColorSpaceRegistry * instance(); virtual ~KoColorSpaceRegistry(); public: /** * add a color space to the registry * @param item the color space factory to add */ void add(KoColorSpaceFactory* item); /** * Remove a color space factory from the registry. Note that it is the * responsibility of the caller to ensure that the colorspaces are not * used anymore. */ void remove(KoColorSpaceFactory* item); /** * Add a profile to the profile map but do not add it to the * color conversion system yet. * @param profile the new profile to be registered. */ void addProfileToMap(KoColorProfile *p); /** * register the profile with the color space registry * @param profile the new profile to be registered so it can be combined with * colorspaces. */ void addProfile(KoColorProfile* profile); void addProfile(const KoColorProfile* profile); // TODO why ? void removeProfile(KoColorProfile* profile); /** * Create an alias to a profile with a different name. Then @ref profileByName * will return the profile @p to when passed @p name as a parameter. */ void addProfileAlias(const QString& name, const QString& to); /** * @return the profile alias, or name if not aliased */ QString profileAlias(const QString& name) const; /** * create a profile of the specified type. */ const KoColorProfile *createColorProfile(const QString & colorModelId, const QString & colorDepthId, const QByteArray& rawData); /** * Return a profile by its given name, or 0 if none registered. * @return a profile by its given name, or 0 if none registered. * @param name the product name as set on the profile. * @see addProfile() * @see KoColorProfile::productName() */ const KoColorProfile * profileByName(const QString & name) const ; /** * Returns a profile by its unique id stored/calculated in the header. * The first call to this function might take long, because the map is * created on the first use only (atm used by SVG only) * @param id unique ProfileID of the profile (MD5 sum of its header) * @return the profile or 0 if not found */ const KoColorProfile *profileByUniqueId(const QByteArray &id) const; bool profileIsCompatible(const KoColorProfile* profile, const QString &colorSpaceId); /** * Return the list of profiles for a colorspace with the argument id. * Profiles will not work with any color space, you can query which profiles * that are registered with this registry can be used in combination with the * argument factory. * @param colorSpaceId the colorspace-id with which all the returned profiles will work. * @return a list of profiles for the factory */ QList profilesFor(const QString& csID) const; QString defaultProfileForColorSpace(const QString &colorSpaceId) const; /** * This function is called by the color space to create a color conversion * between two color space. This function search in the graph of transformations * the best possible path between the two color space. */ KoColorConversionTransformation* createColorConverter(const KoColorSpace * srcColorSpace, const KoColorSpace * dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const; /** * This function creates two transformations, one from the color space and one to the * color space. The destination color space is picked from a list of color space, such * as the conversion between the two color space is of the best quality. * * The typical use case of this function is for KoColorTransformationFactory which * doesn't support all color spaces, so unsupported color space have to find an * acceptable conversion in order to use that KoColorTransformationFactory. * * @param colorSpace the source color space * @param possibilities a list of color space among which we need to find the best * conversion * @param fromCS the conversion from the source color space will be affected to this * variable * @param toCS the revert conversion to the source color space will be affected to this * variable */ void createColorConverters(const KoColorSpace* colorSpace, const QList< QPair >& possibilities, KoColorConversionTransformation*& fromCS, KoColorConversionTransformation*& toCS) const; /** * Return a colorspace that works with the parameter profile. * @param colorSpaceId the ID string of the colorspace that you want to have returned * @param profile the profile be combined with the colorspace * @return the wanted colorspace, or 0 when the cs and profile can not be combined. */ const KoColorSpace * colorSpace(const QString & colorModelId, const QString & colorDepthId, const KoColorProfile *profile); /** * Return a colorspace that works with the parameter profile. * @param profileName the name of the KoColorProfile to be combined with the colorspace * @return the wanted colorspace, or 0 when the cs and profile can not be combined. */ const KoColorSpace * colorSpace(const QString & colorModelId, const QString & colorDepthId, const QString &profileName); const KoColorSpace * colorSpace(const QString & colorModelId, const QString & colorDepthId); /** * Return the id of the colorspace that have the defined colorModelId with colorDepthId. * @param colorModelId id of the color model * @param colorDepthId id of the color depth * @return the id of the wanted colorspace, or "" if no colorspace correspond to those ids */ QString colorSpaceId(const QString & colorModelId, const QString & colorDepthId) const; /** * It's a convenient function that behave like the above. * Return the id of the colorspace that have the defined colorModelId with colorDepthId. * @param colorModelId id of the color model * @param colorDepthId id of the color depth * @return the id of the wanted colorspace, or "" if no colorspace correspond to those ids */ QString colorSpaceId(const KoID& colorModelId, const KoID& colorDepthId) const; /** * @return the identifier of the color model for the given color space id. * * This function is a compatibility function used to get the color space from * all kra files. */ KoID colorSpaceColorModelId(const QString & _colorSpaceId) const; /** * @return the identifier of the color depth for the given color space id. * * This function is a compatibility function used to get the color space from * all kra files. */ KoID colorSpaceColorDepthId(const QString & _colorSpaceId) const; /** * Convenience methods to get the often used alpha colorspaces */ const KoColorSpace *alpha8(); const KoColorSpace *alpha16(); -#include #ifdef HAVE_OPENEXR const KoColorSpace *alpha16f(); #endif const KoColorSpace *alpha32f(); /** * Convenience method to get an RGBA 8bit colorspace. If a profile is not specified, * an sRGB profile will be used. * @param profileName the name of an RGB color profile * @return the wanted colorspace, or 0 if the color space and profile can not be combined. */ const KoColorSpace * rgb8(const QString &profileName = QString()); /** * Convenience method to get an RGBA 8bit colorspace with the given profile. * @param profile an RGB profile * @return the wanted colorspace, or 0 if the color space and profile can not be combined. */ const KoColorSpace * rgb8(const KoColorProfile * profile); /** * Convenience method to get an RGBA 16bit colorspace. If a profile is not specified, * an sRGB profile will be used. * @param profileName the name of an RGB color profile * @return the wanted colorspace, or 0 if the color space and profile can not be combined. */ const KoColorSpace * rgb16(const QString &profileName = QString()); /** * Convenience method to get an RGBA 16bit colorspace with the given profile. * @param profile an RGB profile * @return the wanted colorspace, or 0 if the color space and profile can not be combined. */ const KoColorSpace * rgb16(const KoColorProfile * profile); /** * Convenience method to get an Lab 16bit colorspace. If a profile is not specified, * an Lab profile with a D50 whitepoint will be used. * @param profileName the name of an Lab color profile * @return the wanted colorspace, or 0 if the color space and profile can not be combined. */ const KoColorSpace * lab16(const QString &profileName = QString()); /** * Convenience method to get an Lab 16bit colorspace with the given profile. * @param profile an Lab profile * @return the wanted colorspace, or 0 if the color space and profile can not be combined. */ const KoColorSpace * lab16(const KoColorProfile * profile); /** * @return the list of available color models */ QList colorModelsList(ColorSpaceListVisibility option) const; /** * @return the list of available color models for the given colorModelId */ QList colorDepthList(const KoID& colorModelId, ColorSpaceListVisibility option) const; /** * @return the list of available color models for the given colorModelId */ QList colorDepthList(const QString & colorModelId, ColorSpaceListVisibility option) const; /** * @return the cache of color conversion transformation to be use by KoColorSpace */ KoColorConversionCache* colorConversionCache() const; /** * @return a permanent colorspace owned by the registry, of the same type and profile * as the one given in argument */ const KoColorSpace* permanentColorspace(const KoColorSpace* _colorSpace); /** * This function return a list of all the keys in KoID format by using the name() method * on the objects stored in the registry. */ QList listKeys() const; private: friend class KisCsConversionTest; friend class KisIteratorTest; friend class KisIteratorNGTest; friend class KisPainterTest; friend class KisCrashFilterTest; friend class KoColorSpacesBenchmark; friend class TestKoColorSpaceSanity; friend class TestColorConversionSystem; friend struct FriendOfColorSpaceRegistry; /** * @return a list with an instance of all color space with their default profile. */ QList allColorSpaces(ColorSpaceListVisibility visibility, ColorSpaceListProfilesSelection pSelection); /** * @return the color conversion system use by the registry and the color * spaces to create color conversion transformation. * * WARNING: conversion system is guarded by the registry locks, don't * use it anywhere other than unittests! */ const KoColorConversionSystem* colorConversionSystem() const; private: KoColorSpaceRegistry(const KoColorSpaceRegistry&); KoColorSpaceRegistry operator=(const KoColorSpaceRegistry&); void init(); private: struct Private; Private * const d; }; #endif // KOCOLORSPACEREGISTRY_H diff --git a/libs/pigment/KoConvolutionOpImpl.h b/libs/pigment/KoConvolutionOpImpl.h index 130c4ea8df..4b54d1877e 100644 --- a/libs/pigment/KoConvolutionOpImpl.h +++ b/libs/pigment/KoConvolutionOpImpl.h @@ -1,153 +1,153 @@ /* * Copyright (c) 2006 Cyrille Berger * Copyright (c) 2007 Emanuele Tamponi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KO_CONVOLUTION_OP_IMPL_H #define KO_CONVOLUTION_OP_IMPL_H #include "DebugPigment.h" #include "KoColorSpaceMaths.h" #include "KoConvolutionOp.h" #include "KoColorSpaceTraits.h" template class KoConvolutionOpImpl : public KoConvolutionOp { typedef typename KoColorSpaceMathsTraits::compositetype compositetype; typedef typename _CSTrait::channels_type channels_type; public: KoConvolutionOpImpl() { } ~KoConvolutionOpImpl() override { } /** - * Calculates a weighted average of the pixels, mentioned in @colors - * using weight values from @kernelValues + * Calculates a weighted average of the pixels, mentioned in @p colors + * using weight values from @p kernelValues * * Note: * It behaves in a quite unclear way, when at least one pixel is * fully transparent. There are three cases: * Case A) None of the pixels is fully transparent. - * * Every color channel AND alpha channel of @dst stores a sum - * of the corresponding channels from @colors, divided by @factor - * and incremented by @offset - * Case B) At least one pixel of @colors is transparent and @factor + * * Every color channel AND alpha channel of @p dst stores a sum + * of the corresponding channels from @p colors, divided by @p factor + * and incremented by @p offset + * Case B) At least one pixel of @p colors is transparent and @p factor * stores a weight of the kernel (sum of it's items). - * * Every color channel of @dst stores a sum of the corresponding + * * Every color channel of @p dst stores a sum of the corresponding * channels from non-transparent pixels, divided by a weight - * of non-transparent pixels and incremented by @offset. - * * Alpha channel of @dst stores a sum of the corresponding + * of non-transparent pixels and incremented by @p offset. + * * Alpha channel of @p dst stores a sum of the corresponding * channels from non-transparent pixels, divided by a weight - * of all the pixels (equals to @factor) and incremented - * by @offset. - * Case C) At least one pixel of @colors is transparent and @factor + * of all the pixels (equals to @p factor) and incremented + * by @p offset. + * Case C) At least one pixel of @p colors is transparent and @p factor * is set to an arbitrary value. - * * Every color channel of @dst stores a sum of the corresponding + * * Every color channel of @p dst stores a sum of the corresponding * channels from non-transparent pixels, divided by a "scaled - * down factor" and incremented by @offset. "Scaled + * down factor" and incremented by @p offset. "Scaled * down factor" is calculated in the following way: * * [weight of non-transparent pixels] - * scaledDownFactor = @factor * ---------------------------------- + * scaledDownFactor = @p factor * ---------------------------------- * [weight of all the pixels] * - * * Alpha channel of @dst stores a sum of the corresponding + * * Alpha channel of @p dst stores a sum of the corresponding * channels from non-transparent pixels, divided by unscaled - * @factor and incremented by @offset. + * @p factor and incremented by @p offset. */ void convolveColors(const quint8* const* colors, const qreal* kernelValues, quint8 *dst, qreal factor, qreal offset, qint32 nPixels, const QBitArray & channelFlags) const override { // Create and initialize to 0 the array of totals qreal totals[_CSTrait::channels_nb]; qreal totalWeight = 0; qreal totalWeightTransparent = 0; memset(totals, 0, sizeof(qreal) * _CSTrait::channels_nb); for (; nPixels--; colors++, kernelValues++) { qreal weight = *kernelValues; const channels_type* color = _CSTrait::nativeArray(*colors); if (weight != 0) { if (_CSTrait::opacityU8(*colors) == 0) { totalWeightTransparent += weight; } else { for (uint i = 0; i < _CSTrait::channels_nb; i++) { totals[i] += color[i] * weight; } } totalWeight += weight; } } typename _CSTrait::channels_type* dstColor = _CSTrait::nativeArray(dst); bool allChannels = channelFlags.isEmpty(); Q_ASSERT(allChannels || channelFlags.size() == (int)_CSTrait::channels_nb); if (totalWeightTransparent == 0) { // Case A) for (uint i = 0; i < _CSTrait::channels_nb; i++) { if (allChannels || channelFlags.testBit(i)) { compositetype v = totals[i] / factor + offset; dstColor[ i ] = CLAMP(v, KoColorSpaceMathsTraits::min, KoColorSpaceMathsTraits::max); } } } else if (totalWeightTransparent != totalWeight) { if (totalWeight == factor) { // Case B) qint64 a = (totalWeight - totalWeightTransparent); for (uint i = 0; i < _CSTrait::channels_nb; i++) { if (allChannels || channelFlags.testBit(i)) { if (i == (uint)_CSTrait::alpha_pos) { compositetype v = totals[i] / totalWeight + offset; dstColor[ i ] = CLAMP(v, KoColorSpaceMathsTraits::min, KoColorSpaceMathsTraits::max); } else { compositetype v = totals[i] / a + offset; dstColor[ i ] = CLAMP(v, KoColorSpaceMathsTraits::min, KoColorSpaceMathsTraits::max); } } } } else { // Case C) qreal a = qreal(totalWeight) / (factor * (totalWeight - totalWeightTransparent)); // use qreal as it easily saturate for (uint i = 0; i < _CSTrait::channels_nb; i++) { if (allChannels || channelFlags.testBit(i)) { if (i == (uint)_CSTrait::alpha_pos) { compositetype v = totals[i] / factor + offset; dstColor[ i ] = CLAMP(v, KoColorSpaceMathsTraits::min, KoColorSpaceMathsTraits::max); } else { compositetype v = (compositetype)(totals[i] * a + offset); dstColor[ i ] = CLAMP(v, KoColorSpaceMathsTraits::min, KoColorSpaceMathsTraits::max); } } } } } } }; #endif diff --git a/libs/pigment/compositeops/KoStreamedMath.h b/libs/pigment/compositeops/KoStreamedMath.h index c1c8d427c7..a3dc731814 100644 --- a/libs/pigment/compositeops/KoStreamedMath.h +++ b/libs/pigment/compositeops/KoStreamedMath.h @@ -1,427 +1,427 @@ /* * Copyright (c) 2012 Dmitry Kazakov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef __KOSTREAMED_MATH_H #define __KOSTREAMED_MATH_H #if defined _MSC_VER // Lets shut up the "possible loss of data" and "forcing value to bool 'true' or 'false' #pragma warning ( push ) #pragma warning ( disable : 4244 ) #pragma warning ( disable : 4800 ) #endif #include #include #if defined _MSC_VER #pragma warning ( pop ) #endif #include #include #include #define BLOCKDEBUG 0 #if !defined _MSC_VER #pragma GCC diagnostic ignored "-Wcast-align" #endif template struct KoStreamedMath { using int_v = Vc::SimdArray; using uint_v = Vc::SimdArray; /** * Composes src into dst without using vector instructions */ template static void genericComposite_novector(const KoCompositeOp::ParameterInfo& params) { using namespace Arithmetic; const qint32 linearInc = pixelSize; qint32 srcLinearInc = params.srcRowStride ? pixelSize : 0; quint8* dstRowStart = params.dstRowStart; const quint8* maskRowStart = params.maskRowStart; const quint8* srcRowStart = params.srcRowStart; typename Compositor::OptionalParams optionalParams(params); for(quint32 r=params.rows; r>0; --r) { const quint8 *mask = maskRowStart; const quint8 *src = srcRowStart; quint8 *dst = dstRowStart; int blockRest = params.cols; for(int i = 0; i < blockRest; i++) { Compositor::template compositeOnePixelScalar(src, dst, mask, params.opacity, optionalParams); src += srcLinearInc; dst += linearInc; if (useMask) { mask++; } } srcRowStart += params.srcRowStride; dstRowStart += params.dstRowStride; if (useMask) { maskRowStart += params.maskRowStride; } } } template static void genericComposite32_novector(const KoCompositeOp::ParameterInfo& params) { genericComposite_novector(params); } template static void genericComposite128_novector(const KoCompositeOp::ParameterInfo& params) { genericComposite_novector(params); } static inline quint8 round_float_to_uint(float value) { return quint8(value + float(0.5)); } static inline quint8 lerp_mixed_u8_float(quint8 a, quint8 b, float alpha) { return round_float_to_uint(qint16(b - a) * alpha + a); } /** * Get a vector containing first Vc::float_v::size() values of mask. * Each source mask element is considered to be a 8-bit integer */ static inline Vc::float_v fetch_mask_8(const quint8 *data) { uint_v data_i(data); return Vc::simd_cast(int_v(data_i)); } /** * Get an alpha values from Vc::float_v::size() pixels 32-bit each * (4 channels, 8 bit per channel). The alpha value is considered * to be stored in the most significant byte of the pixel * * \p aligned controls whether the \p data is fetched using aligned * instruction or not. * 1) Fetching aligned data with unaligned instruction * degrades performance. * 2) Fetching unaligned data with aligned instruction - * causes #GP (General Protection Exception) + * causes \#GP (General Protection Exception) */ template static inline Vc::float_v fetch_alpha_32(const quint8 *data) { uint_v data_i; if (aligned) { data_i.load((const quint32*)data, Vc::Aligned); } else { data_i.load((const quint32*)data, Vc::Unaligned); } return Vc::simd_cast(int_v(data_i >> 24)); } /** * Get color values from Vc::float_v::size() pixels 32-bit each * (4 channels, 8 bit per channel). The color data is considered * to be stored in the 3 least significant bytes of the pixel. * * \p aligned controls whether the \p data is fetched using aligned * instruction or not. * 1) Fetching aligned data with unaligned instruction * degrades performance. * 2) Fetching unaligned data with aligned instruction - * causes #GP (General Protection Exception) + * causes \#GP (General Protection Exception) */ template static inline void fetch_colors_32(const quint8 *data, Vc::float_v &c1, Vc::float_v &c2, Vc::float_v &c3) { int_v data_i; if (aligned) { data_i.load((const quint32*)data, Vc::Aligned); } else { data_i.load((const quint32*)data, Vc::Unaligned); } const quint32 lowByteMask = 0xFF; uint_v mask(lowByteMask); c1 = Vc::simd_cast(int_v((data_i >> 16) & mask)); c2 = Vc::simd_cast(int_v((data_i >> 8) & mask)); c3 = Vc::simd_cast(int_v( data_i & mask)); } /** * Pack color and alpha values to Vc::float_v::size() pixels 32-bit each * (4 channels, 8 bit per channel). The color data is considered * to be stored in the 3 least significant bytes of the pixel, alpha - * in the most significant byte * * NOTE: \p data must be aligned pointer! */ static inline void write_channels_32(quint8 *data, Vc::float_v::AsArg alpha, Vc::float_v::AsArg c1, Vc::float_v::AsArg c2, Vc::float_v::AsArg c3) { /** * FIXME: make conversion float->int * use methematical rounding */ const quint32 lowByteMask = 0xFF; // FIXME: Use single-instruction rounding + conversion // The achieve that we need to implement Vc::iRound() uint_v mask(lowByteMask); uint_v v1 = uint_v(int_v(Vc::round(alpha))) << 24; uint_v v2 = (uint_v(int_v(Vc::round(c1))) & mask) << 16; uint_v v3 = (uint_v(int_v(Vc::round(c2))) & mask) << 8; uint_v v4 = uint_v(int_v(Vc::round(c3))) & mask; v1 = v1 | v2; v3 = v3 | v4; (v1 | v3).store((quint32*)data, Vc::Aligned); } /** * Composes src pixels into dst pixles. Is optimized for 32-bit-per-pixel * colorspaces. Uses \p Compositor strategy parameter for doing actual * math of the composition */ template static void genericComposite(const KoCompositeOp::ParameterInfo& params) { using namespace Arithmetic; const int vectorSize = Vc::float_v::size(); const qint32 vectorInc = pixelSize * vectorSize; const qint32 linearInc = pixelSize; qint32 srcVectorInc = vectorInc; qint32 srcLinearInc = pixelSize; quint8* dstRowStart = params.dstRowStart; const quint8* maskRowStart = params.maskRowStart; const quint8* srcRowStart = params.srcRowStart; typename Compositor::OptionalParams optionalParams(params); if (!params.srcRowStride) { if (pixelSize == 4) { quint32 *buf = Vc::malloc(vectorSize); *((uint_v*)buf) = uint_v(*((const quint32*)params.srcRowStart)); srcRowStart = reinterpret_cast(buf); srcLinearInc = 0; srcVectorInc = 0; } else { quint8 *buf = Vc::malloc(vectorInc); quint8 *ptr = buf; for (int i = 0; i < vectorSize; i++) { memcpy(ptr, params.srcRowStart, pixelSize); ptr += pixelSize; } srcRowStart = buf; srcLinearInc = 0; srcVectorInc = 0; } } #if BLOCKDEBUG int totalBlockAlign = 0; int totalBlockAlignedVector = 0; int totalBlockUnalignedVector = 0; int totalBlockRest = 0; #endif for(quint32 r=params.rows; r>0; --r) { // Hint: Mask is allowed to be unaligned const quint8 *mask = maskRowStart; const quint8 *src = srcRowStart; quint8 *dst = dstRowStart; const int pixelsAlignmentMask = vectorSize * sizeof(float) - 1; uintptr_t srcPtrValue = reinterpret_cast(src); uintptr_t dstPtrValue = reinterpret_cast(dst); uintptr_t srcAlignment = srcPtrValue & pixelsAlignmentMask; uintptr_t dstAlignment = dstPtrValue & pixelsAlignmentMask; // Uncomment if facing problems with alignment: // Q_ASSERT_X(!(dstAlignment & 3), "Compositioning", // "Pixel data must be aligned on pixels borders!"); int blockAlign = params.cols; int blockAlignedVector = 0; int blockUnalignedVector = 0; int blockRest = 0; int *vectorBlock = srcAlignment == dstAlignment || !srcVectorInc ? &blockAlignedVector : &blockUnalignedVector; if (!dstAlignment) { blockAlign = 0; *vectorBlock = params.cols / vectorSize; blockRest = params.cols % vectorSize; } else if (params.cols > 2 * vectorSize) { blockAlign = (vectorInc - dstAlignment) / pixelSize; const int restCols = params.cols - blockAlign; if (restCols > 0) { *vectorBlock = restCols / vectorSize; blockRest = restCols % vectorSize; } else { blockAlign = params.cols; *vectorBlock = 0; blockRest = 0; } } #if BLOCKDEBUG totalBlockAlign += blockAlign; totalBlockAlignedVector += blockAlignedVector; totalBlockUnalignedVector += blockUnalignedVector; totalBlockRest += blockRest; #endif for(int i = 0; i < blockAlign; i++) { Compositor::template compositeOnePixelScalar(src, dst, mask, params.opacity, optionalParams); src += srcLinearInc; dst += linearInc; if(useMask) { mask++; } } for (int i = 0; i < blockAlignedVector; i++) { Compositor::template compositeVector(src, dst, mask, params.opacity, optionalParams); src += srcVectorInc; dst += vectorInc; if (useMask) { mask += vectorSize; } } for (int i = 0; i < blockUnalignedVector; i++) { Compositor::template compositeVector(src, dst, mask, params.opacity, optionalParams); src += srcVectorInc; dst += vectorInc; if (useMask) { mask += vectorSize; } } for(int i = 0; i < blockRest; i++) { Compositor::template compositeOnePixelScalar(src, dst, mask, params.opacity, optionalParams); src += srcLinearInc; dst += linearInc; if (useMask) { mask++; } } srcRowStart += params.srcRowStride; dstRowStart += params.dstRowStride; if (useMask) { maskRowStart += params.maskRowStride; } } #if BLOCKDEBUG dbgPigment << "I" << "rows:" << params.rows << "\tpad(S):" << totalBlockAlign << "\tbav(V):" << totalBlockAlignedVector << "\tbuv(V):" << totalBlockUnalignedVector << "\tres(S)" << totalBlockRest; // << srcAlignment << dstAlignment; #endif if (!params.srcRowStride) { Vc::free(reinterpret_cast(const_cast(srcRowStart))); } } template static void genericComposite32(const KoCompositeOp::ParameterInfo& params) { genericComposite(params); } template static void genericComposite128(const KoCompositeOp::ParameterInfo& params) { genericComposite(params); } }; namespace KoStreamedMathFunctions { template ALWAYS_INLINE void clearPixel(quint8* dst); template<> ALWAYS_INLINE void clearPixel<4>(quint8* dst) { quint32 *d = reinterpret_cast(dst); *d = 0; } template<> ALWAYS_INLINE void clearPixel<16>(quint8* dst) { quint64 *d = reinterpret_cast(dst); d[0] = 0; d[1] = 0; } template ALWAYS_INLINE void copyPixel(const quint8 *src, quint8* dst); template<> ALWAYS_INLINE void copyPixel<4>(const quint8 *src, quint8* dst) { const quint32 *s = reinterpret_cast(src); quint32 *d = reinterpret_cast(dst); *d = *s; } template<> ALWAYS_INLINE void copyPixel<16>(const quint8 *src, quint8* dst) { const quint64 *s = reinterpret_cast(src); quint64 *d = reinterpret_cast(dst); d[0] = s[0]; d[1] = s[1]; } } #endif /* __KOSTREAMED_MATH_H */ diff --git a/libs/pigment/resources/KisSwatchGroup.h b/libs/pigment/resources/KisSwatchGroup.h index de32624bdd..e98515edea 100644 --- a/libs/pigment/resources/KisSwatchGroup.h +++ b/libs/pigment/resources/KisSwatchGroup.h @@ -1,127 +1,127 @@ /* This file is part of the KDE project Copyright (c) 2005 Boudewijn Rempt Copyright (c) 2016 L. E. Segovia Copyright (c) 2018 Michael Zhou This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef KISSWATCHGROUP_H #define KISSWATCHGROUP_H #include "KisSwatch.h" #include "kritapigment_export.h" #include #include #include #include /** * @brief The KisSwatchGroup class stores a matrix of color swatches * swatches can accessed using (x, y) coordinates. * x is the column number from left to right and y is the row number from top * to bottom. * Both x and y start at 0 * there could be empty entries, so the checkEntry(int, int) method must used * whenever you want to get an entry from the matrix */ class KRITAPIGMENT_EXPORT KisSwatchGroup { public /* struct */: struct SwatchInfo { QString group; KisSwatch swatch; int row; int column; }; public: KisSwatchGroup(); ~KisSwatchGroup(); KisSwatchGroup(const KisSwatchGroup &rhs); KisSwatchGroup &operator =(const KisSwatchGroup &rhs); public /* methods */: void setName(const QString &name); QString name() const; void setColumnCount(int columnCount); int columnCount() const; void setRowCount(int newRowCount); int rowCount() const; int colorCount() const; QList infoList() const; /** * @brief checkEntry - * checks if position x and y has a valid entry - * both x and y start from 0 - * @param x - * @param y - * @return true if there is a valid entry at position (x, y) + * checks if position @p column and @p row has a valid entry + * both @p column and @p row start from 0 + * @param column + * @param row + * @return true if there is a valid entry at position (column, row) */ bool checkEntry(int column, int row) const; /** * @brief setEntry - * sets the entry at position (x, y) to be e + * sets the entry at position (@p column, @p row) to be @p e * @param e - * @param x - * @param y + * @param column + * @param row */ void setEntry(const KisSwatch &e, int column, int row); /** * @brief getEntry - * used to get the swatch entry at position (x, y) + * used to get the swatch entry at position (@p column, @p row) * there is an assertion to make sure that this position isn't empty, * so checkEntry(int, int) must be used before this method to ensure * a valid entry can be found - * @param x - * @param y - * @return the swatch entry at position (x, y) + * @param column + * @param row + * @return the swatch entry at position (column, row) */ KisSwatch getEntry(int column, int row) const; /** * @brief removeEntry - * removes the entry at position (x, y) - * @param x - * @param y - * @return true if these is an entry at (x, y) + * removes the entry at position (@p column, @p row) + * @param column + * @param row + * @return true if these is an entry at (column, row) */ bool removeEntry(int column, int row); /** * @brief addEntry * adds the entry e to the right of the rightmost entry in the last row * if the rightmost entry in the last row is in the right most column, * add e to the leftmost column of a new row * * when column is set to 0, resize number of columns to default * @param e */ void addEntry(const KisSwatch &e); void clear(); private /* member variables */: struct Private; QScopedPointer d; }; #endif // KISSWATCHGROUP_H diff --git a/libs/pigment/resources/KoColorSet.h b/libs/pigment/resources/KoColorSet.h index aa8a2bff8f..8d927f93e3 100644 --- a/libs/pigment/resources/KoColorSet.h +++ b/libs/pigment/resources/KoColorSet.h @@ -1,219 +1,222 @@ /* This file is part of the KDE project Copyright (c) 2005 Boudewijn Rempt Copyright (c) 2016 L. E. Segovia This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef KOCOLORSET #define KOCOLORSET #include #include #include #include #include #include #include "KoColor.h" #include "KisSwatch.h" #include "KisSwatchGroup.h" /** * Also called palette. * Open Gimp, Photoshop or RIFF palette files. This is a straight port * from the Gimp. */ class KRITAPIGMENT_EXPORT KoColorSet :public KoResource { public: static const QString GLOBAL_GROUP_NAME; static const QString KPL_VERSION_ATTR; static const QString KPL_GROUP_ROW_COUNT_ATTR; static const QString KPL_PALETTE_COLUMN_COUNT_ATTR; static const QString KPL_PALETTE_NAME_ATTR; static const QString KPL_PALETTE_COMMENT_ATTR; static const QString KPL_PALETTE_FILENAME_ATTR; static const QString KPL_PALETTE_READONLY_ATTR; static const QString KPL_COLOR_MODEL_ID_ATTR; static const QString KPL_COLOR_DEPTH_ID_ATTR; static const QString KPL_GROUP_NAME_ATTR; static const QString KPL_SWATCH_ROW_ATTR; static const QString KPL_SWATCH_COL_ATTR; static const QString KPL_SWATCH_NAME_ATTR; static const QString KPL_SWATCH_SPOT_ATTR; static const QString KPL_SWATCH_ID_ATTR; static const QString KPL_SWATCH_BITDEPTH_ATTR; static const QString KPL_PALETTE_PROFILE_TAG; static const QString KPL_SWATCH_POS_TAG; static const QString KPL_SWATCH_TAG; static const QString KPL_GROUP_TAG; static const QString KPL_PALETTE_TAG; public: enum PaletteType { UNKNOWN = 0, GPL, // GIMP RIFF_PAL, // RIFF ACT, // Photoshop binary PSP_PAL, // PaintShop Pro ACO, // Photoshop Swatches XML, // XML palette (Scribus) KPL, // KoColor-based XML palette SBZ // SwatchBooker }; /** * Load a color set from a file. This can be a Gimp * palette, a RIFF palette, a Photoshop palette, * a Krita palette, * a Scribus palette or a SwatchBooker palette. */ explicit KoColorSet(const QString &filename = QString()); // Explicit copy constructor (KoResource copy constructor is private) KoColorSet(const KoColorSet& rhs); public /* overridden methods */: // KoResource ~KoColorSet() override; bool load() override; bool loadFromDevice(QIODevice *dev) override; bool save() override; bool saveToDevice(QIODevice* dev) const override; QString defaultFileExtension() const override; public /* methods */: void setColumnCount(int columns); int columnCount() const; void setComment(QString comment); QString comment(); int rowCount() const; quint32 colorCount() const; PaletteType paletteType() const; void setPaletteType(PaletteType paletteType); /** * @brief isGlobal * A global color set is a set stored in the config directory * Such a color set would be opened every time Krita is launched. * * A non-global color set, on contrary, would be stored in a kra file, * and would only be opened when that file is opened by Krita. - * @return + * @return @c true if the set is global */ bool isGlobal() const; void setIsGlobal(bool); bool isEditable() const; void setIsEditable(bool isEditable); QByteArray toByteArray() const; bool fromByteArray(QByteArray &data); /** - * @brief add Add a color to the palette. + * @brief Add a color to the palette. + * @param c the swatch * @param groupName color to add the group to. If empty, it will be added to the unsorted. */ void add(const KisSwatch &, const QString &groupName = GLOBAL_GROUP_NAME); void setEntry(const KisSwatch &e, int x, int y, const QString &groupName = GLOBAL_GROUP_NAME); /** * @brief getColorGlobal - * A function for getting a color based on a global index. Useful for itterating through all color entries. - * @param globalIndex the global index over the whole palette. + * A function for getting a color based on a global index. Useful for iterating through all color entries. + * @param x the global x index over the whole palette. + * @param y the global y index over the whole palette. * @return the entry. */ KisSwatch getColorGlobal(quint32 x, quint32 y) const; /** * @brief getColorGroup * A function for getting the color from a specific group. - * @param groupName the name of the group, will give unosrted when not defined. - * @param index the index within the group. + * @param x the x index over the group. + * @param y the y index over the group. + * @param groupName the name of the group, will give unsorted when not defined. * @return the entry */ KisSwatch getColorGroup(quint32 x, quint32 y, QString groupName); /** * @brief getGroupNames * @return returns a list of group names, excluding the unsorted group. */ QStringList getGroupNames(); /** * @brief getGroup * @param name * @return the group with the name given; global group if no parameter is given * null pointer if not found. */ KisSwatchGroup *getGroup(const QString &name); KisSwatchGroup *getGlobalGroup(); bool changeGroupName(const QString &oldGroupName, const QString &newGroupName); /** * @brief addGroup * Adds a new group. * @param groupName the name of the new group. When not specified, this will fail. * @return whether thegroup was made. */ bool addGroup(const QString &groupName); /** * @brief moveGroup * Move a group in the internal stringlist. * @param groupName the groupname to move. * @param groupNameInsertBefore the groupname to insert before. Empty means it will be added to the end. * @return */ bool moveGroup(const QString &groupName, const QString &groupNameInsertBefore = GLOBAL_GROUP_NAME); /** * @brief removeGroup * Remove a group from the KoColorSet * @param groupName the name of the group you want to remove. * @param keepColors Whether you wish to keep the colorsetentries. These will be added to the unsorted. * @return whether it could find the group to remove. */ bool removeGroup(const QString &groupName, bool keepColors = true); void clear(); /** * @brief getIndexClosestColor * function that matches the color to all colors in the colorset, and returns the index * of the closest match. - * @param color the color you wish to compare. + * @param compare the color you wish to compare. * @param useGivenColorSpace whether to use the color space of the color given * when the two colors' colorspaces don't match. Else it'll use the entry's colorspace. * @return returns the int of the closest match. */ KisSwatchGroup::SwatchInfo getClosestColorInfo(KoColor compare, bool useGivenColorSpace = true); private: class Private; const QScopedPointer d; }; typedef QSharedPointer KoColorSetSP; #endif // KOCOLORSET diff --git a/libs/store/KoStore_p.h b/libs/store/KoStore_p.h index 75b5f6ef58..4a6c6e0ff4 100644 --- a/libs/store/KoStore_p.h +++ b/libs/store/KoStore_p.h @@ -1,107 +1,107 @@ /* This file is part of the KDE project Copyright 2004 Nicolas GOUTTE This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef __koStore_p_h_ #define __koStore_p_h_ #include "KoStore.h" #include #include #include class QWidget; class KoStorePrivate { public: explicit KoStorePrivate(KoStore *qq, KoStore::Mode _mode, bool _writeMimetype) : q(qq), window(0), mode(_mode), size(0), stream(0), isOpen(false), good(false), finalized(false), writeMimetype(_writeMimetype) { } /** * Conversion routine - * @param _internalNaming name used internally : "root", "tar:/0", ... + * @param internalNaming name used internally : "root", "tar:/0", ... * @return the name used in the file, more user-friendly ("maindoc.xml", * "part0/maindoc.xml", ...) * Examples: * * tar:/0 is saved as part0/maindoc.xml * tar:/0/1 is saved as part0/part1/maindoc.xml * tar:/0/1/pictures/picture0.png is saved as part0/part1/pictures/picture0.png * * see specification (calligra/lib/store/SPEC) for details. */ QString toExternalNaming(const QString &internalNaming) const; /** * Enter *one* single directory. Nothing like foo/bar/bleh allowed. * Performs some checking when in Read mode */ bool enterDirectoryInternal(const QString &directory); bool extractFile(const QString &sourceName, QIODevice &buffer); KoStore *q; /** * original URL of the remote file * (undefined for a local file) */ QUrl url; QString localFileName; QWidget *window; KoStore::Mode mode; /// Store the filenames (with full path inside the archive) when writing, to avoid duplicates QStringList filesList; /// The "current directory" (path) QStringList currentPath; /// Current filename (between an open() and a close()) QString fileName; /// Current size of the file named m_sName qint64 size; /// The stream for the current read or write operation QIODevice *stream; bool isOpen; /// Must be set by the constructor. bool good; bool finalized; QStack directoryStack; bool writeMimetype; ///< true if the backend is allowed to create "mimetype" automatically. }; #endif diff --git a/libs/store/KoXmlReader.h b/libs/store/KoXmlReader.h index aa0f888348..e31d61ccc1 100644 --- a/libs/store/KoXmlReader.h +++ b/libs/store/KoXmlReader.h @@ -1,181 +1,183 @@ /* This file is part of the KDE project Copyright (C) 2005-2006 Ariya Hidayat This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KO_XMLREADER_H #define KO_XMLREADER_H #include "KoXmlReaderForward.h" #include "kritastore_export.h" #include #include class QIODevice; /** * The office-text-content-prelude type. */ enum KoXmlNamedItemType { KoXmlTextContentPrelude ///< office-text-content-prelude //KoXmlTextContentMain, ///< office-text-content-main //KoXmlTextContentEpilogue ///< office-text-content-epilogue }; /** * This namespace contains a few convenience functions to simplify code using QDom * (when loading OASIS documents, in particular). * * To find the child element with a given name, use KoXml::namedItemNS. * * To find all child elements with a given name, use * QDomElement e; * forEachElement( e, parent ) * { * if ( e.localName() == "..." && e.namespaceURI() == KoXmlNS::... ) * { * ... * } * } * Note that this means you don't ever need to use QDomNode nor toElement anymore! * Also note that localName is the part without the prefix, this is the whole point * of namespace-aware methods. * * To find the attribute with a given name, use QDomElement::attributeNS. * * Do not use getElementsByTagNameNS, it's recursive (which is never needed in Calligra). * Do not use tagName() or nodeName() or prefix(), since the prefix isn't fixed. * * @author David Faure */ namespace KoXml { /** * A namespace-aware version of QDomNode::namedItem(), * which also takes care of casting to a QDomElement. * * Use this when a domelement is known to have only *one* child element * with a given tagname. * * Note: do *NOT* use getElementsByTagNameNS, it's recursive! */ KRITASTORE_EXPORT KoXmlElement namedItemNS(const KoXmlNode& node, const QString& nsURI, const QString& localName); /** * A namespace-aware version of QDomNode::namedItem(). * which also takes care of casting to a QDomElement. * * Use this when you like to return the first or an invalid * KoXmlElement with a known type. * * This is an optimized version of the namedItemNS above to * give fast access to certain sections of the document using * the office-text-content-prelude condition as @a KoXmlNamedItemType . */ KRITASTORE_EXPORT KoXmlElement namedItemNS(const KoXmlNode& node, const QString& nsURI, const QString& localName, KoXmlNamedItemType type); /** * Explicitly load child nodes of specified node, up to given depth. * This function has no effect if QDom is used. */ KRITASTORE_EXPORT void load(KoXmlNode& node, int depth = 1); /** * Unload child nodes of specified node. * This function has no effect if QDom is used. */ KRITASTORE_EXPORT void unload(KoXmlNode& node); /** * Get the number of child nodes of specified node. */ KRITASTORE_EXPORT int childNodesCount(const KoXmlNode& node); /** * Return the name of all attributes of specified node. */ KRITASTORE_EXPORT QStringList attributeNames(const KoXmlNode& node); /** * Convert KoXmlNode classes to the corresponding QDom classes, which has * @p ownerDoc as the owner document (QDomDocument instance). * The converted @p node (and its children) are added to ownerDoc. * * NOTE: * - If ownerDoc is not empty, this may fail, @see QDomDocument * - @p node must not be a KoXmlDocument, use asQDomDocument() * * @see asQDomDocument, asQDomElement */ KRITASTORE_EXPORT void asQDomNode(QDomDocument& ownerDoc, const KoXmlNode& node); /** * Convert KoXmlNode classes to the corresponding QDom classes, which has * @p ownerDoc as the owner document (QDomDocument instance). * The converted @p element (and its children) is added to ownerDoc. * * NOTE: If ownerDoc is not empty, this may fail, @see QDomDocument * */ KRITASTORE_EXPORT void asQDomElement(QDomDocument& ownerDoc, const KoXmlElement& element); /** * Converts the whole @p document into a QDomDocument */ KRITASTORE_EXPORT QDomDocument asQDomDocument(const KoXmlDocument& document); /* * Load an XML document from specified device to a document. You can of * course use it with QFile (which inherits QIODevice). * This is much more memory efficient than standard QDomDocument::setContent * because the data from the device is buffered, unlike * QDomDocument::setContent which just loads everything in memory. * * Note: it is assumed that the XML uses UTF-8 encoding. */ KRITASTORE_EXPORT bool setDocument(KoXmlDocument& doc, QIODevice* device, bool namespaceProcessing, QString* errorMsg = 0, int* errorLine = 0, int* errorColumn = 0); } /** * \def forEachElement( elem, parent ) - * \brief Loop through all child elements of \parent. + * \brief Loop through all child elements of \p parent. * This convenience macro is used to implement the forEachElement loop. - * The \elem parameter is a name of a QDomElement variable and the \parent + * The \p elem parameter is a name of a QDomElement variable and the \p parent * is the name of the parent element. For example: * + * \code * QDomElement e; * forEachElement( e, parent ) * { * qDebug() << e.localName() << " element found."; * ... * } + * \endcode */ #define forEachElement( elem, parent ) \ for ( KoXmlNode _node = parent.firstChild(); !_node.isNull(); _node = _node.nextSibling() ) \ if ( ( elem = _node.toElement() ).isNull() ) {} else #endif // KO_XMLREADER_H diff --git a/libs/store/KoXmlVector.h b/libs/store/KoXmlVector.h index a004638760..5e6bc2bd46 100644 --- a/libs/store/KoXmlVector.h +++ b/libs/store/KoXmlVector.h @@ -1,176 +1,176 @@ /* This file is part of the KDE project Copyright (C) 2005-2006 Ariya Hidayat This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KO_XMLVECTOR_H #define KO_XMLVECTOR_H // comment it to test this class without the compression #define KOXMLVECTOR_USE_LZF #ifdef KOXMLVECTOR_USE_LZF #include "KoLZF.h" #endif #include #include #include #include /** * KoXmlVector * * similar to QVector, but using LZF compression to save memory space * this class is however not reentrant * * Needs to be used like this, otherwise will crash: - * + *
    *
  • add content with newItem()
  • *
  • finish adding content with squeeze()
  • *
  • just read content with operator[]
  • - * + *
* * @param uncompressedItemCount when number of buffered items reach this, * compression will start small value will give better memory usage at the * cost of speed bigger value will be better in term of speed, but use * more memory */ template class KoXmlVector { private: unsigned m_totalItems; QVector m_startIndex; QVector m_blocks; mutable unsigned m_bufferStartIndex; mutable QVector m_bufferItems; mutable QByteArray m_bufferData; protected: /** * fetch given item index to the buffer * will INVALIDATE all references to the buffer */ void fetchItem(unsigned index) const { // already in the buffer ? if (index >= m_bufferStartIndex) if (index - m_bufferStartIndex < (unsigned)m_bufferItems.count()) return; // search in the stored blocks // TODO: binary search to speed up int loc = m_startIndex.count() - 1; for (int c = 0; c < m_startIndex.count() - 1; ++c) if (index >= m_startIndex[c]) if (index < m_startIndex[c+1]) { loc = c; break; } m_bufferStartIndex = m_startIndex[loc]; #ifdef KOXMLVECTOR_USE_LZF KoLZF::decompress(m_blocks[loc], m_bufferData); #else m_bufferData = m_blocks[loc]; #endif QBuffer buffer(&m_bufferData); buffer.open(QIODevice::ReadOnly); QDataStream in(&buffer); m_bufferItems.clear(); in >> m_bufferItems; } /** * store data in the buffer to main m_blocks */ void storeBuffer() { QBuffer buffer; buffer.open(QIODevice::WriteOnly); QDataStream out(&buffer); out << m_bufferItems; m_startIndex.append(m_bufferStartIndex); #ifdef KOXMLVECTOR_USE_LZF m_blocks.append(KoLZF::compress(buffer.data())); #else m_blocks.append(buffer.data()); #endif m_bufferStartIndex += m_bufferItems.count(); m_bufferItems.clear(); } public: inline KoXmlVector(): m_totalItems(0), m_bufferStartIndex(0) {}; void clear() { m_totalItems = 0; m_startIndex.clear(); m_blocks.clear(); m_bufferStartIndex = 0; m_bufferItems.clear(); m_bufferData.reserve(reservedBufferSize); } inline int count() const { return (int)m_totalItems; } inline int size() const { return (int)m_totalItems; } inline bool isEmpty() const { return m_totalItems == 0; } /** * append a new item * WARNING: use the return value as soon as possible * it may be invalid if another function is invoked */ T& newItem() { // buffer full? if (m_bufferItems.count() >= uncompressedItemCount - 1) storeBuffer(); ++m_totalItems; m_bufferItems.resize(m_bufferItems.count() + 1); return m_bufferItems[m_bufferItems.count()-1]; } /** * WARNING: use the return value as soon as possible * it may be invalid if another function is invoked */ const T &operator[](int i) const { fetchItem((unsigned)i); return m_bufferItems[i - m_bufferStartIndex]; } /** * optimize memory usage * will INVALIDATE all references to the buffer */ void squeeze() { storeBuffer(); } }; #endif diff --git a/libs/ui/KisMainWindow.cpp b/libs/ui/KisMainWindow.cpp index 229e6c53b1..afd5cb90b7 100644 --- a/libs/ui/KisMainWindow.cpp +++ b/libs/ui/KisMainWindow.cpp @@ -1,2667 +1,2681 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Torben Weis Copyright (C) 2000-2006 David Faure Copyright (C) 2007, 2009 Thomas zander Copyright (C) 2010 Benjamin Port This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KisMainWindow.h" #include // qt 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 #include #include #include #include #include #include #include #include #include "kis_selection_manager.h" #include "kis_icon_utils.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KoDockFactoryBase.h" #include "KoDocumentInfoDlg.h" #include "KoDocumentInfo.h" #include "KoFileDialog.h" #include #include #include #include #include #include "KoToolDocker.h" #include "KoToolBoxDocker_p.h" #include #include #include #include #include #include #include #include "dialogs/kis_about_application.h" #include "dialogs/kis_delayed_save_dialog.h" #include "dialogs/kis_dlg_preferences.h" #include "kis_action.h" #include "kis_action_manager.h" #include "KisApplication.h" #include "kis_canvas2.h" #include "kis_canvas_controller.h" #include "kis_canvas_resource_provider.h" #include "kis_clipboard.h" #include "kis_config.h" #include "kis_config_notifier.h" #include "kis_custom_image_widget.h" #include #include "kis_group_layer.h" #include "kis_image_from_clipboard_widget.h" #include "kis_image.h" #include #include "KisImportExportManager.h" #include "kis_mainwindow_observer.h" #include "kis_memory_statistics_server.h" #include "kis_node.h" #include "KisOpenPane.h" #include "kis_paintop_box.h" #include "KisPart.h" #include "KisPrintJob.h" #include "KisResourceServerProvider.h" #include "kis_signal_compressor_with_param.h" #include "kis_statusbar.h" #include "KisView.h" #include "KisViewManager.h" #include "thememanager.h" #include "kis_animation_importer.h" #include "dialogs/kis_dlg_import_image_sequence.h" #include #include "KisWindowLayoutManager.h" #include #include "KisWelcomePageWidget.h" #include #include #include #ifdef Q_OS_WIN #include #endif class ToolDockerFactory : public KoDockFactoryBase { public: ToolDockerFactory() : KoDockFactoryBase() { } QString id() const override { return "sharedtooldocker"; } QDockWidget* createDockWidget() override { KoToolDocker* dockWidget = new KoToolDocker(); return dockWidget; } DockPosition defaultDockPosition() const override { return DockRight; } }; class Q_DECL_HIDDEN KisMainWindow::Private { public: Private(KisMainWindow *parent, QUuid id) : q(parent) , id(id) , dockWidgetMenu(new KActionMenu(i18nc("@action:inmenu", "&Dockers"), parent)) , windowMenu(new KActionMenu(i18nc("@action:inmenu", "&Window"), parent)) , documentMenu(new KActionMenu(i18nc("@action:inmenu", "New &View"), parent)) , workspaceMenu(new KActionMenu(i18nc("@action:inmenu", "Wor&kspace"), parent)) , welcomePage(new KisWelcomePageWidget(parent)) , widgetStack(new QStackedWidget(parent)) , mdiArea(new QMdiArea(parent)) , windowMapper(new QSignalMapper(parent)) , documentMapper(new QSignalMapper(parent)) { if (id.isNull()) this->id = QUuid::createUuid(); widgetStack->addWidget(welcomePage); widgetStack->addWidget(mdiArea); mdiArea->setTabsMovable(true); mdiArea->setActivationOrder(QMdiArea::ActivationHistoryOrder); } ~Private() { qDeleteAll(toolbarList); } KisMainWindow *q {0}; QUuid id; KisViewManager *viewManager {0}; QPointer activeView; QList toolbarList; bool firstTime {true}; bool windowSizeDirty {false}; bool readOnly {false}; KisAction *showDocumentInfo {0}; KisAction *saveAction {0}; KisAction *saveActionAs {0}; // KisAction *printAction; // KisAction *printActionPreview; // KisAction *exportPdf {0}; KisAction *importAnimation {0}; KisAction *closeAll {0}; // KisAction *reloadFile; KisAction *importFile {0}; KisAction *exportFile {0}; KisAction *undo {0}; KisAction *redo {0}; KisAction *newWindow {0}; KisAction *close {0}; KisAction *mdiCascade {0}; KisAction *mdiTile {0}; KisAction *mdiNextWindow {0}; KisAction *mdiPreviousWindow {0}; KisAction *toggleDockers {0}; KisAction *toggleDockerTitleBars {0}; KisAction *fullScreenMode {0}; KisAction *showSessionManager {0}; KisAction *expandingSpacers[2]; KActionMenu *dockWidgetMenu; KActionMenu *windowMenu; KActionMenu *documentMenu; KActionMenu *workspaceMenu; KHelpMenu *helpMenu {0}; KRecentFilesAction *recentFiles {0}; KoLegacyResourceModel *workspacemodel {0}; QScopedPointer undoActionsUpdateManager; QString lastExportLocation; QMap dockWidgetsMap; QByteArray dockerStateBeforeHiding; KoToolDocker *toolOptionsDocker {0}; QCloseEvent *deferredClosingEvent {0}; Digikam::ThemeManager *themeManager {0}; KisWelcomePageWidget *welcomePage {0}; QStackedWidget *widgetStack {0}; QMdiArea *mdiArea; QMdiSubWindow *activeSubWindow {0}; QSignalMapper *windowMapper; QSignalMapper *documentMapper; QByteArray lastExportedFormat; QScopedPointer > tabSwitchCompressor; QMutex savingEntryMutex; KConfigGroup windowStateConfig; QUuid workspaceBorrowedBy; KisSignalAutoConnectionsStore screenConnectionsStore; KisActionManager * actionManager() { return viewManager->actionManager(); } QTabBar* findTabBarHACK() { QObjectList objects = mdiArea->children(); Q_FOREACH (QObject *object, objects) { QTabBar *bar = qobject_cast(object); if (bar) { return bar; } } return 0; } }; KisMainWindow::KisMainWindow(QUuid uuid) : KXmlGuiWindow() , d(new Private(this, uuid)) { auto rserver = KisResourceServerProvider::instance()->workspaceServer(); QSharedPointer adapter(new KoResourceServerAdapter(rserver)); d->workspacemodel = new KoLegacyResourceModel(adapter, this); connect(d->workspacemodel, &KoLegacyResourceModel::afterResourcesLayoutReset, this, [&]() { updateWindowMenu(); }); d->viewManager = new KisViewManager(this, actionCollection()); KConfigGroup group( KSharedConfig::openConfig(), "theme"); d->themeManager = new Digikam::ThemeManager(group.readEntry("Theme", "Krita dark"), this); d->windowStateConfig = KSharedConfig::openConfig()->group("MainWindow"); setAcceptDrops(true); setStandardToolBarMenuEnabled(true); setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North); setDockNestingEnabled(true); qApp->setStartDragDistance(25); // 25 px is a distance that works well for Tablet and Mouse events #ifdef Q_OS_OSX setUnifiedTitleAndToolBarOnMac(true); #endif connect(this, SIGNAL(restoringDone()), this, SLOT(forceDockTabFonts())); connect(this, SIGNAL(themeChanged()), d->viewManager, SLOT(updateIcons())); connect(KisPart::instance(), SIGNAL(documentClosed(QString)), SLOT(updateWindowMenu())); connect(KisPart::instance(), SIGNAL(documentOpened(QString)), SLOT(updateWindowMenu())); connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), this, SLOT(configChanged())); actionCollection()->addAssociatedWidget(this); KoPluginLoader::instance()->load("Krita/ViewPlugin", "Type == 'Service' and ([X-Krita-Version] == 28)", KoPluginLoader::PluginsConfig(), d->viewManager, false); // Load the per-application plugins (Right now, only Python) We do this only once, when the first mainwindow is being created. KoPluginLoader::instance()->load("Krita/ApplicationPlugin", "Type == 'Service' and ([X-Krita-Version] == 28)", KoPluginLoader::PluginsConfig(), qApp, true); KoToolBoxFactory toolBoxFactory; QDockWidget *toolbox = createDockWidget(&toolBoxFactory); toolbox->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetClosable); KisConfig cfg(true); if (cfg.toolOptionsInDocker()) { ToolDockerFactory toolDockerFactory; d->toolOptionsDocker = qobject_cast(createDockWidget(&toolDockerFactory)); d->toolOptionsDocker->toggleViewAction()->setEnabled(true); } QMap dockwidgetActions; dockwidgetActions[toolbox->toggleViewAction()->text()] = toolbox->toggleViewAction(); Q_FOREACH (const QString & docker, KoDockRegistry::instance()->keys()) { KoDockFactoryBase *factory = KoDockRegistry::instance()->value(docker); QDockWidget *dw = createDockWidget(factory); dockwidgetActions[dw->toggleViewAction()->text()] = dw->toggleViewAction(); } if (d->toolOptionsDocker) { dockwidgetActions[d->toolOptionsDocker->toggleViewAction()->text()] = d->toolOptionsDocker->toggleViewAction(); } connect(KoToolManager::instance(), SIGNAL(toolOptionWidgetsChanged(KoCanvasController*,QList >)), this, SLOT(newOptionWidgets(KoCanvasController*,QList >))); Q_FOREACH (QString title, dockwidgetActions.keys()) { d->dockWidgetMenu->addAction(dockwidgetActions[title]); } Q_FOREACH (QDockWidget *wdg, dockWidgets()) { if ((wdg->features() & QDockWidget::DockWidgetClosable) == 0) { wdg->setVisible(true); } } Q_FOREACH (KoCanvasObserverBase* observer, canvasObservers()) { observer->setObservedCanvas(0); KisMainwindowObserver* mainwindowObserver = dynamic_cast(observer); if (mainwindowObserver) { mainwindowObserver->setViewManager(d->viewManager); } } // Load all the actions from the tool plugins Q_FOREACH(KoToolFactoryBase *toolFactory, KoToolRegistry::instance()->values()) { toolFactory->createActions(actionCollection()); } d->mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); d->mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); d->mdiArea->setTabPosition(QTabWidget::North); d->mdiArea->setTabsClosable(true); // Tab close button override // Windows just has a black X, and Ubuntu has a dark x that is hard to read // just switch this icon out for all OSs so it is easier to see d->mdiArea->setStyleSheet("QTabBar::close-button { image: url(:/pics/broken-preset.png) }"); setCentralWidget(d->widgetStack); d->widgetStack->setCurrentIndex(0); connect(d->mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(subWindowActivated())); connect(d->windowMapper, SIGNAL(mapped(QWidget*)), this, SLOT(setActiveSubWindow(QWidget*))); connect(d->documentMapper, SIGNAL(mapped(QObject*)), this, SLOT(newView(QObject*))); createActions(); // the welcome screen needs to grab actions...so make sure this line goes after the createAction() so they exist d->welcomePage->setMainWindow(this); setAutoSaveSettings(d->windowStateConfig, false); subWindowActivated(); updateWindowMenu(); if (isHelpMenuEnabled() && !d->helpMenu) { // workaround for KHelpMenu (or rather KAboutData::applicationData()) internally // not using the Q*Application metadata ATM, which results e.g. in the bugreport wizard // not having the app version preset // fixed hopefully in KF5 5.22.0, patch pending QGuiApplication *app = qApp; KAboutData aboutData(app->applicationName(), app->applicationDisplayName(), app->applicationVersion()); aboutData.setOrganizationDomain(app->organizationDomain().toUtf8()); d->helpMenu = new KHelpMenu(this, aboutData, false); // workaround-less version: // d->helpMenu = new KHelpMenu(this, QString()/*unused*/, false); // The difference between using KActionCollection->addAction() is that // these actions do not get tied to the MainWindow. What does this all do? KActionCollection *actions = d->viewManager->actionCollection(); QAction *helpContentsAction = d->helpMenu->action(KHelpMenu::menuHelpContents); QAction *whatsThisAction = d->helpMenu->action(KHelpMenu::menuWhatsThis); QAction *reportBugAction = d->helpMenu->action(KHelpMenu::menuReportBug); QAction *switchLanguageAction = d->helpMenu->action(KHelpMenu::menuSwitchLanguage); QAction *aboutAppAction = d->helpMenu->action(KHelpMenu::menuAboutApp); QAction *aboutKdeAction = d->helpMenu->action(KHelpMenu::menuAboutKDE); if (helpContentsAction) { actions->addAction(helpContentsAction->objectName(), helpContentsAction); } if (whatsThisAction) { actions->addAction(whatsThisAction->objectName(), whatsThisAction); } if (reportBugAction) { actions->addAction(reportBugAction->objectName(), reportBugAction); } if (switchLanguageAction) { actions->addAction(switchLanguageAction->objectName(), switchLanguageAction); } if (aboutAppAction) { actions->addAction(aboutAppAction->objectName(), aboutAppAction); } if (aboutKdeAction) { actions->addAction(aboutKdeAction->objectName(), aboutKdeAction); } connect(d->helpMenu, SIGNAL(showAboutApplication()), SLOT(showAboutApplication())); } // KDE' libs 4''s help contents action is broken outside kde, for some reason... We can handle it just as easily ourselves QAction *helpAction = actionCollection()->action("help_contents"); helpAction->disconnect(); connect(helpAction, SIGNAL(triggered()), this, SLOT(showManual())); #if 0 //check for colliding shortcuts QSet existingShortcuts; Q_FOREACH (QAction* action, actionCollection()->actions()) { if(action->shortcut() == QKeySequence(0)) { continue; } dbgKrita << "shortcut " << action->text() << " " << action->shortcut(); Q_ASSERT(!existingShortcuts.contains(action->shortcut())); existingShortcuts.insert(action->shortcut()); } #endif configChanged(); // If we have customized the toolbars, load that first setLocalXMLFile(KoResourcePaths::locateLocal("data", "krita4.xmlgui")); setXMLFile(":/kxmlgui5/krita4.xmlgui"); guiFactory()->addClient(this); // Create and plug toolbar list for Settings menu QList toolbarList; Q_FOREACH (QWidget* it, guiFactory()->containers("ToolBar")) { KToolBar * toolBar = ::qobject_cast(it); toolBar->setMovable(KisConfig(true).readEntry("LockAllDockerPanels", false)); if (toolBar) { if (toolBar->objectName() == "BrushesAndStuff") { toolBar->setEnabled(false); } KToggleAction* act = new KToggleAction(i18n("Show %1 Toolbar", toolBar->windowTitle()), this); actionCollection()->addAction(toolBar->objectName().toUtf8(), act); act->setCheckedState(KGuiItem(i18n("Hide %1 Toolbar", toolBar->windowTitle()))); connect(act, SIGNAL(toggled(bool)), this, SLOT(slotToolbarToggled(bool))); act->setChecked(!toolBar->isHidden()); toolbarList.append(act); } else { warnUI << "Toolbar list contains a " << it->metaObject()->className() << " which is not a toolbar!"; } } KToolBar::setToolBarsLocked(KisConfig(true).readEntry("LockAllDockerPanels", false)); plugActionList("toolbarlist", toolbarList); d->toolbarList = toolbarList; applyToolBarLayout(); d->viewManager->updateGUI(); d->viewManager->updateIcons(); #ifdef Q_OS_WIN auto w = qApp->activeWindow(); if (w) QWindowsWindowFunctions::setHasBorderInFullScreen(w->windowHandle(), true); #endif QTimer::singleShot(1000, this, SLOT(checkSanity())); { using namespace std::placeholders; // For _1 placeholder std::function callback( std::bind(&KisMainWindow::switchTab, this, _1)); d->tabSwitchCompressor.reset( new KisSignalCompressorWithParam(500, callback, KisSignalCompressor::FIRST_INACTIVE)); } + + + if (cfg.readEntry("CanvasOnlyActive", false)) { + QString currentWorkspace = cfg.readEntry("CurrentWorkspace", "Default"); + KoResourceServer * rserver = KisResourceServerProvider::instance()->workspaceServer(); + KisWorkspaceResource* workspace = rserver->resourceByName(currentWorkspace); + if (workspace) { + restoreWorkspace(workspace); + } + cfg.writeEntry("CanvasOnlyActive", false); + menuBar()->setVisible(true); + } + + } KisMainWindow::~KisMainWindow() { // Q_FOREACH (QAction *ac, actionCollection()->actions()) { // QAction *action = qobject_cast(ac); // if (action) { // qDebug() << "", "").replace("", "") // << "\n\ticonText=" << action->iconText().replace("&", "&") // << "\n\tshortcut=" << action->shortcut().toString() // << "\n\tisCheckable=" << QString((action->isChecked() ? "true" : "false")) // << "\n\tstatusTip=" << action->statusTip() // << "\n/>\n" ; // } // else { // dbgKrita << "Got a non-qaction:" << ac->objectName(); // } // } // The doc and view might still exist (this is the case when closing the window) KisPart::instance()->removeMainWindow(this); delete d->viewManager; delete d; } QUuid KisMainWindow::id() const { return d->id; } void KisMainWindow::addView(KisView *view) { if (d->activeView == view) return; if (d->activeView) { d->activeView->disconnect(this); } // register the newly created view in the input manager viewManager()->inputManager()->addTrackedCanvas(view->canvasBase()); showView(view); updateCaption(); emit restoringDone(); if (d->activeView) { connect(d->activeView, SIGNAL(titleModified(QString,bool)), SLOT(slotDocumentTitleModified())); connect(d->viewManager->statusBar(), SIGNAL(memoryStatusUpdated()), this, SLOT(updateCaption())); } } void KisMainWindow::notifyChildViewDestroyed(KisView *view) { viewManager()->inputManager()->removeTrackedCanvas(view->canvasBase()); if (view->canvasBase() == viewManager()->canvasBase()) { viewManager()->setCurrentView(0); } } void KisMainWindow::showView(KisView *imageView) { if (imageView && activeView() != imageView) { // XXX: find a better way to initialize this! imageView->setViewManager(d->viewManager); imageView->canvasBase()->setFavoriteResourceManager(d->viewManager->paintOpBox()->favoriteResourcesManager()); imageView->slotLoadingFinished(); QMdiSubWindow *subwin = d->mdiArea->addSubWindow(imageView); imageView->setSubWindow(subwin); subwin->setAttribute(Qt::WA_DeleteOnClose, true); connect(subwin, SIGNAL(destroyed()), SLOT(updateWindowMenu())); KisConfig cfg(true); subwin->setOption(QMdiSubWindow::RubberBandMove, cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); subwin->setOption(QMdiSubWindow::RubberBandResize, cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); subwin->setWindowIcon(qApp->windowIcon()); /** * Hack alert! * * Here we explicitly request KoToolManager to emit all the tool * activation signals, to reinitialize the tool options docker. * * That is needed due to a design flaw we have in the * initialization procedure. The tool in the KoToolManager is * initialized in KisView::setViewManager() calls, which * happens early enough. During this call the tool manager * requests KoCanvasControllerWidget to emit the signal to * update the widgets in the tool docker. *But* at that moment * of time the view is not yet connected to the main window, * because it happens in KisViewManager::setCurrentView a bit * later. This fact makes the widgets updating signals be lost * and never reach the tool docker. * * So here we just explicitly call the tool activation stub. */ KoToolManager::instance()->initializeCurrentToolForCanvas(); if (d->mdiArea->subWindowList().size() == 1) { imageView->showMaximized(); } else { imageView->show(); } // No, no, no: do not try to call this _before_ the show() has // been called on the view; only when that has happened is the // opengl context active, and very bad things happen if we tell // the dockers to update themselves with a view if the opengl // context is not active. setActiveView(imageView); updateWindowMenu(); updateCaption(); } } void KisMainWindow::slotPreferences() { if (KisDlgPreferences::editPreferences()) { KisConfigNotifier::instance()->notifyConfigChanged(); KisConfigNotifier::instance()->notifyPixelGridModeChanged(); KisImageConfigNotifier::instance()->notifyConfigChanged(); // XXX: should this be changed for the views in other windows as well? Q_FOREACH (QPointer koview, KisPart::instance()->views()) { KisViewManager *view = qobject_cast(koview); if (view) { // Update the settings for all nodes -- they don't query // KisConfig directly because they need the settings during // compositing, and they don't connect to the config notifier // because nodes are not QObjects (because only one base class // can be a QObject). KisNode* node = dynamic_cast(view->image()->rootLayer().data()); node->updateSettings(); } } d->viewManager->showHideScrollbars(); } } void KisMainWindow::slotThemeChanged() { // save theme changes instantly KConfigGroup group( KSharedConfig::openConfig(), "theme"); group.writeEntry("Theme", d->themeManager->currentThemeName()); // reload action icons! Q_FOREACH (QAction *action, actionCollection()->actions()) { KisIconUtils::updateIcon(action); } emit themeChanged(); } void KisMainWindow::updateReloadFileAction(KisDocument *doc) { Q_UNUSED(doc); // d->reloadFile->setEnabled(doc && !doc->url().isEmpty()); } void KisMainWindow::setReadWrite(bool readwrite) { d->saveAction->setEnabled(readwrite); d->importFile->setEnabled(readwrite); d->readOnly = !readwrite; updateCaption(); } void KisMainWindow::addRecentURL(const QUrl &url) { // Add entry to recent documents list // (call coming from KisDocument because it must work with cmd line, template dlg, file/open, etc.) if (!url.isEmpty()) { bool ok = true; if (url.isLocalFile()) { QString path = url.adjusted(QUrl::StripTrailingSlash).toLocalFile(); const QStringList tmpDirs = KoResourcePaths::resourceDirs("tmp"); for (QStringList::ConstIterator it = tmpDirs.begin() ; ok && it != tmpDirs.end() ; ++it) { if (path.contains(*it)) { ok = false; // it's in the tmp resource } } const QStringList templateDirs = KoResourcePaths::findDirs("templates"); for (QStringList::ConstIterator it = templateDirs.begin() ; ok && it != templateDirs.end() ; ++it) { if (path.contains(*it)) { ok = false; // it's in the templates directory. break; } } } if (ok) { d->recentFiles->addUrl(url); } saveRecentFiles(); } } void KisMainWindow::saveRecentFiles() { // Save list of recent files KSharedConfigPtr config = KSharedConfig::openConfig(); d->recentFiles->saveEntries(config->group("RecentFiles")); config->sync(); // Tell all windows to reload their list, after saving // Doesn't work multi-process, but it's a start Q_FOREACH (KisMainWindow *mw, KisPart::instance()->mainWindows()) { if (mw != this) { mw->reloadRecentFileList(); } } } QList KisMainWindow::recentFilesUrls() { return d->recentFiles->urls(); } void KisMainWindow::clearRecentFiles() { d->recentFiles->clear(); } void KisMainWindow::reloadRecentFileList() { d->recentFiles->loadEntries(KSharedConfig::openConfig()->group("RecentFiles")); } void KisMainWindow::updateCaption() { if (!d->mdiArea->activeSubWindow()) { updateCaption(QString(), false); } else if (d->activeView && d->activeView->document() && d->activeView->image()){ KisDocument *doc = d->activeView->document(); QString caption(doc->caption()); if (d->readOnly) { caption += " [" + i18n("Write Protected") + "] "; } if (doc->isRecovered()) { caption += " [" + i18n("Recovered") + "] "; } // show the file size for the document KisMemoryStatisticsServer::Statistics m_fileSizeStats = KisMemoryStatisticsServer::instance()->fetchMemoryStatistics(d->activeView ? d->activeView->image() : 0); if (m_fileSizeStats.imageSize) { caption += QString(" (").append( KFormat().formatByteSize(m_fileSizeStats.imageSize)).append( ")"); } d->activeView->setWindowTitle(caption); d->activeView->setWindowModified(doc->isModified()); updateCaption(caption, doc->isModified()); if (!doc->url().fileName().isEmpty()) { d->saveAction->setToolTip(i18n("Save as %1", doc->url().fileName())); } else { d->saveAction->setToolTip(i18n("Save")); } } } void KisMainWindow::updateCaption(const QString & caption, bool mod) { dbgUI << "KisMainWindow::updateCaption(" << caption << "," << mod << ")"; QString versionString = KritaVersionWrapper::versionString(true); #if defined(KRITA_ALPHA) || defined (KRITA_BETA) || defined (KRITA_RC) setCaption(QString("%1: %2").arg(versionString).arg(caption), mod); return; #endif setCaption(caption, mod); } KisView *KisMainWindow::activeView() const { if (d->activeView) { return d->activeView; } return 0; } bool KisMainWindow::openDocument(const QUrl &url, OpenFlags flags) { if (!QFile(url.toLocalFile()).exists()) { if (!(flags & BatchMode)) { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("The file %1 does not exist.", url.url())); } d->recentFiles->removeUrl(url); //remove the file from the recent-opened-file-list saveRecentFiles(); return false; } return openDocumentInternal(url, flags); } bool KisMainWindow::openDocumentInternal(const QUrl &url, OpenFlags flags) { if (!url.isLocalFile()) { qWarning() << "KisMainWindow::openDocumentInternal. Not a local file:" << url; return false; } KisDocument *newdoc = KisPart::instance()->createDocument(); if (flags & BatchMode) { newdoc->setFileBatchMode(true); } d->firstTime = true; connect(newdoc, SIGNAL(completed()), this, SLOT(slotLoadCompleted())); connect(newdoc, SIGNAL(canceled(QString)), this, SLOT(slotLoadCanceled(QString))); KisDocument::OpenFlags openFlags = KisDocument::None; if (flags & RecoveryFile) { openFlags |= KisDocument::RecoveryFile; } bool openRet = !(flags & Import) ? newdoc->openUrl(url, openFlags) : newdoc->importDocument(url); if (!openRet) { delete newdoc; return false; } KisPart::instance()->addDocument(newdoc); updateReloadFileAction(newdoc); if (!QFileInfo(url.toLocalFile()).isWritable()) { setReadWrite(false); } return true; } void KisMainWindow::showDocument(KisDocument *document) { Q_FOREACH(QMdiSubWindow *subwindow, d->mdiArea->subWindowList()) { KisView *view = qobject_cast(subwindow->widget()); KIS_SAFE_ASSERT_RECOVER_NOOP(view); if (view) { if (view->document() == document) { setActiveSubWindow(subwindow); return; } } } addViewAndNotifyLoadingCompleted(document); } KisView* KisMainWindow::addViewAndNotifyLoadingCompleted(KisDocument *document) { showWelcomeScreen(false); // see workaround in function header KisView *view = KisPart::instance()->createView(document, resourceManager(), actionCollection(), this); addView(view); emit guiLoadingFinished(); return view; } QStringList KisMainWindow::showOpenFileDialog(bool isImporting) { KoFileDialog dialog(this, KoFileDialog::ImportFiles, "OpenDocument"); dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); dialog.setMimeTypeFilters(KisImportExportManager::supportedMimeTypes(KisImportExportManager::Import)); dialog.setCaption(isImporting ? i18n("Import Images") : i18n("Open Images")); return dialog.filenames(); } // Separate from openDocument to handle async loading (remote URLs) void KisMainWindow::slotLoadCompleted() { KisDocument *newdoc = qobject_cast(sender()); if (newdoc && newdoc->image()) { addViewAndNotifyLoadingCompleted(newdoc); disconnect(newdoc, SIGNAL(completed()), this, SLOT(slotLoadCompleted())); disconnect(newdoc, SIGNAL(canceled(QString)), this, SLOT(slotLoadCanceled(QString))); emit loadCompleted(); } } void KisMainWindow::slotLoadCanceled(const QString & errMsg) { dbgUI << "KisMainWindow::slotLoadCanceled"; if (!errMsg.isEmpty()) // empty when canceled by user QMessageBox::critical(this, i18nc("@title:window", "Krita"), errMsg); // ... can't delete the document, it's the one who emitted the signal... KisDocument* doc = qobject_cast(sender()); Q_ASSERT(doc); disconnect(doc, SIGNAL(completed()), this, SLOT(slotLoadCompleted())); disconnect(doc, SIGNAL(canceled(QString)), this, SLOT(slotLoadCanceled(QString))); } void KisMainWindow::slotSaveCanceled(const QString &errMsg) { dbgUI << "KisMainWindow::slotSaveCanceled"; if (!errMsg.isEmpty()) // empty when canceled by user QMessageBox::critical(this, i18nc("@title:window", "Krita"), errMsg); slotSaveCompleted(); } void KisMainWindow::slotSaveCompleted() { dbgUI << "KisMainWindow::slotSaveCompleted"; KisDocument* doc = qobject_cast(sender()); Q_ASSERT(doc); disconnect(doc, SIGNAL(completed()), this, SLOT(slotSaveCompleted())); disconnect(doc, SIGNAL(canceled(QString)), this, SLOT(slotSaveCanceled(QString))); if (d->deferredClosingEvent) { KXmlGuiWindow::closeEvent(d->deferredClosingEvent); } } bool KisMainWindow::hackIsSaving() const { StdLockableWrapper wrapper(&d->savingEntryMutex); std::unique_lock> l(wrapper, std::try_to_lock); return !l.owns_lock(); } bool KisMainWindow::installBundle(const QString &fileName) const { QFileInfo from(fileName); QFileInfo to(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/bundles/" + from.fileName()); if (to.exists()) { QFile::remove(to.canonicalFilePath()); } return QFile::copy(fileName, QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/bundles/" + from.fileName()); } bool KisMainWindow::saveDocument(KisDocument *document, bool saveas, bool isExporting) { if (!document) { return true; } /** * Make sure that we cannot enter this method twice! * * The lower level functions may call processEvents() so * double-entry is quite possible to achieve. Here we try to lock * the mutex, and if it is failed, just cancel saving. */ StdLockableWrapper wrapper(&d->savingEntryMutex); std::unique_lock> l(wrapper, std::try_to_lock); if (!l.owns_lock()) return false; // no busy wait for saving because it is dangerous! KisDelayedSaveDialog dlg(document->image(), KisDelayedSaveDialog::SaveDialog, 0, this); dlg.blockIfImageIsBusy(); if (dlg.result() == KisDelayedSaveDialog::Rejected) { return false; } else if (dlg.result() == KisDelayedSaveDialog::Ignored) { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("You are saving a file while the image is " "still rendering. The saved file may be " "incomplete or corrupted.\n\n" "Please select a location where the original " "file will not be overridden!")); saveas = true; } if (document->isRecovered()) { saveas = true; } if (document->url().isEmpty()) { saveas = true; } connect(document, SIGNAL(completed()), this, SLOT(slotSaveCompleted())); connect(document, SIGNAL(canceled(QString)), this, SLOT(slotSaveCanceled(QString))); QByteArray nativeFormat = document->nativeFormatMimeType(); QByteArray oldMimeFormat = document->mimeType(); QUrl suggestedURL = document->url(); QStringList mimeFilter = KisImportExportManager::supportedMimeTypes(KisImportExportManager::Export); mimeFilter = KisImportExportManager::supportedMimeTypes(KisImportExportManager::Export); if (!mimeFilter.contains(oldMimeFormat)) { dbgUI << "KisMainWindow::saveDocument no export filter for" << oldMimeFormat; // --- don't setOutputMimeType in case the user cancels the Save As // dialog and then tries to just plain Save --- // suggest a different filename extension (yes, we fortunately don't all live in a world of magic :)) QString suggestedFilename = QFileInfo(suggestedURL.toLocalFile()).baseName(); if (!suggestedFilename.isEmpty()) { // ".kra" looks strange for a name suggestedFilename = suggestedFilename + "." + KisMimeDatabase::suffixesForMimeType(KIS_MIME_TYPE).first(); suggestedURL = suggestedURL.adjusted(QUrl::RemoveFilename); suggestedURL.setPath(suggestedURL.path() + suggestedFilename); } // force the user to choose outputMimeType saveas = true; } bool ret = false; if (document->url().isEmpty() || isExporting || saveas) { // if you're just File/Save As'ing to change filter options you // don't want to be reminded about overwriting files etc. bool justChangingFilterOptions = false; KoFileDialog dialog(this, KoFileDialog::SaveFile, "SaveAs"); dialog.setCaption(isExporting ? i18n("Exporting") : i18n("Saving As")); //qDebug() << ">>>>>" << isExporting << d->lastExportLocation << d->lastExportedFormat << QString::fromLatin1(document->mimeType()); if (isExporting && !d->lastExportLocation.isEmpty()) { // Use the location where we last exported to, if it's set, as the opening location for the file dialog QString proposedPath = QFileInfo(d->lastExportLocation).absolutePath(); // If the document doesn't have a filename yet, use the title QString proposedFileName = suggestedURL.isEmpty() ? document->documentInfo()->aboutInfo("title") : QFileInfo(suggestedURL.toLocalFile()).baseName(); // Use the last mimetype we exported to by default QString proposedMimeType = d->lastExportedFormat.isEmpty() ? "" : d->lastExportedFormat; QString proposedExtension = KisMimeDatabase::suffixesForMimeType(proposedMimeType).first().remove("*,"); // Set the default dir: this overrides the one loaded from the config file, since we're exporting and the lastExportLocation is not empty dialog.setDefaultDir(proposedPath + "/" + proposedFileName + "." + proposedExtension, true); dialog.setMimeTypeFilters(mimeFilter, proposedMimeType); } else { // Get the last used location for saving KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs"); QString proposedPath = group.readEntry("SaveAs", ""); // if that is empty, get the last used location for loading if (proposedPath.isEmpty()) { proposedPath = group.readEntry("OpenDocument", ""); } // If that is empty, too, use the Pictures location. if (proposedPath.isEmpty()) { proposedPath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation); } // But only use that if the suggestedUrl, that is, the document's own url is empty, otherwise // open the location where the document currently is. dialog.setDefaultDir(suggestedURL.isEmpty() ? proposedPath : suggestedURL.toLocalFile(), true); // If exporting, default to all supported file types if user is exporting QByteArray default_mime_type = ""; if (!isExporting) { // otherwise use the document's mimetype, or if that is empty, kra, which is the savest. default_mime_type = document->mimeType().isEmpty() ? nativeFormat : document->mimeType(); } dialog.setMimeTypeFilters(mimeFilter, QString::fromLatin1(default_mime_type)); } QUrl newURL = QUrl::fromUserInput(dialog.filename()); if (newURL.isLocalFile()) { QString fn = newURL.toLocalFile(); if (QFileInfo(fn).completeSuffix().isEmpty()) { fn.append(KisMimeDatabase::suffixesForMimeType(nativeFormat).first()); newURL = QUrl::fromLocalFile(fn); } } if (document->documentInfo()->aboutInfo("title") == i18n("Unnamed")) { QString fn = newURL.toLocalFile(); QFileInfo info(fn); document->documentInfo()->setAboutInfo("title", info.baseName()); } QByteArray outputFormat = nativeFormat; QString outputFormatString = KisMimeDatabase::mimeTypeForFile(newURL.toLocalFile(), false); outputFormat = outputFormatString.toLatin1(); if (!isExporting) { justChangingFilterOptions = (newURL == document->url()) && (outputFormat == document->mimeType()); } else { QString path = QFileInfo(d->lastExportLocation).absolutePath(); QString filename = QFileInfo(document->url().toLocalFile()).baseName(); justChangingFilterOptions = (QFileInfo(newURL.toLocalFile()).absolutePath() == path) && (QFileInfo(newURL.toLocalFile()).baseName() == filename) && (outputFormat == d->lastExportedFormat); } bool bOk = true; if (newURL.isEmpty()) { bOk = false; } if (bOk) { bool wantToSave = true; // don't change this line unless you know what you're doing :) if (!justChangingFilterOptions) { if (!document->isNativeFormat(outputFormat)) wantToSave = true; } if (wantToSave) { if (!isExporting) { // Save As ret = document->saveAs(newURL, outputFormat, true); if (ret) { dbgUI << "Successful Save As!"; KisPart::instance()->addRecentURLToAllMainWindows(newURL); setReadWrite(true); } else { dbgUI << "Failed Save As!"; } } else { // Export ret = document->exportDocument(newURL, outputFormat); if (ret) { d->lastExportLocation = newURL.toLocalFile(); d->lastExportedFormat = outputFormat; } } } // if (wantToSave) { else ret = false; } // if (bOk) { else ret = false; } else { // saving // We cannot "export" into the currently // opened document. We are not Gimp. KIS_ASSERT_RECOVER_NOOP(!isExporting); // be sure document has the correct outputMimeType! if (document->isModified()) { ret = document->save(true, 0); } if (!ret) { dbgUI << "Failed Save!"; } } updateReloadFileAction(document); updateCaption(); return ret; } void KisMainWindow::undo() { if (activeView()) { activeView()->document()->undoStack()->undo(); } } void KisMainWindow::redo() { if (activeView()) { activeView()->document()->undoStack()->redo(); } } void KisMainWindow::closeEvent(QCloseEvent *e) { if (!KisPart::instance()->closingSession()) { QAction *action= d->viewManager->actionCollection()->action("view_show_canvas_only"); if ((action) && (action->isChecked())) { action->setChecked(false); } // Save session when last window is closed if (KisPart::instance()->mainwindowCount() == 1) { bool closeAllowed = KisPart::instance()->closeSession(); if (!closeAllowed) { e->setAccepted(false); return; } } } d->mdiArea->closeAllSubWindows(); QList childrenList = d->mdiArea->subWindowList(); if (childrenList.isEmpty()) { d->deferredClosingEvent = e; saveWindowState(true); } else { e->setAccepted(false); } } void KisMainWindow::saveWindowSettings() { KSharedConfigPtr config = KSharedConfig::openConfig(); if (d->windowSizeDirty ) { dbgUI << "KisMainWindow::saveWindowSettings"; KConfigGroup group = d->windowStateConfig; KWindowConfig::saveWindowSize(windowHandle(), group); config->sync(); d->windowSizeDirty = false; } if (!d->activeView || d->activeView->document()) { // Save toolbar position into the config file of the app, under the doc's component name KConfigGroup group = d->windowStateConfig; saveMainWindowSettings(group); // Save collapsible state of dock widgets for (QMap::const_iterator i = d->dockWidgetsMap.constBegin(); i != d->dockWidgetsMap.constEnd(); ++i) { if (i.value()->widget()) { KConfigGroup dockGroup = group.group(QString("DockWidget ") + i.key()); dockGroup.writeEntry("Collapsed", i.value()->widget()->isHidden()); dockGroup.writeEntry("Locked", i.value()->property("Locked").toBool()); dockGroup.writeEntry("DockArea", (int) dockWidgetArea(i.value())); dockGroup.writeEntry("xPosition", (int) i.value()->widget()->x()); dockGroup.writeEntry("yPosition", (int) i.value()->widget()->y()); dockGroup.writeEntry("width", (int) i.value()->widget()->width()); dockGroup.writeEntry("height", (int) i.value()->widget()->height()); } } } KSharedConfig::openConfig()->sync(); resetAutoSaveSettings(); // Don't let KMainWindow override the good stuff we wrote down } void KisMainWindow::resizeEvent(QResizeEvent * e) { d->windowSizeDirty = true; KXmlGuiWindow::resizeEvent(e); } void KisMainWindow::setActiveView(KisView* view) { d->activeView = view; updateCaption(); if (d->undoActionsUpdateManager) { d->undoActionsUpdateManager->setCurrentDocument(view ? view->document() : 0); } d->viewManager->setCurrentView(view); KisWindowLayoutManager::instance()->activeDocumentChanged(view->document()); } void KisMainWindow::dragEnterEvent(QDragEnterEvent *event) { d->welcomePage->showDropAreaIndicator(true); if (event->mimeData()->hasUrls() || event->mimeData()->hasFormat("application/x-krita-node") || event->mimeData()->hasFormat("application/x-qt-image")) { event->accept(); } } void KisMainWindow::dropEvent(QDropEvent *event) { d->welcomePage->showDropAreaIndicator(false); if (event->mimeData()->hasUrls() && event->mimeData()->urls().size() > 0) { Q_FOREACH (const QUrl &url, event->mimeData()->urls()) { if (url.toLocalFile().endsWith(".bundle")) { bool r = installBundle(url.toLocalFile()); if (!r) { qWarning() << "Could not install bundle" << url.toLocalFile(); } } else { openDocument(url, None); } } } } void KisMainWindow::dragMoveEvent(QDragMoveEvent * event) { QTabBar *tabBar = d->findTabBarHACK(); if (!tabBar && d->mdiArea->viewMode() == QMdiArea::TabbedView) { qWarning() << "WARNING!!! Cannot find QTabBar in the main window! Looks like Qt has changed behavior. Drag & Drop between multiple tabs might not work properly (tabs will not switch automatically)!"; } if (tabBar && tabBar->isVisible()) { QPoint pos = tabBar->mapFromGlobal(mapToGlobal(event->pos())); if (tabBar->rect().contains(pos)) { const int tabIndex = tabBar->tabAt(pos); if (tabIndex >= 0 && tabBar->currentIndex() != tabIndex) { d->tabSwitchCompressor->start(tabIndex); } } else if (d->tabSwitchCompressor->isActive()) { d->tabSwitchCompressor->stop(); } } } void KisMainWindow::dragLeaveEvent(QDragLeaveEvent * /*event*/) { d->welcomePage->showDropAreaIndicator(false); if (d->tabSwitchCompressor->isActive()) { d->tabSwitchCompressor->stop(); } } void KisMainWindow::switchTab(int index) { QTabBar *tabBar = d->findTabBarHACK(); if (!tabBar) return; tabBar->setCurrentIndex(index); } void KisMainWindow::showWelcomeScreen(bool show) { d->widgetStack->setCurrentIndex(!show); } void KisMainWindow::slotFileNew() { const QStringList mimeFilter = KisImportExportManager::supportedMimeTypes(KisImportExportManager::Import); KisOpenPane *startupWidget = new KisOpenPane(this, mimeFilter, QStringLiteral("templates/")); startupWidget->setWindowModality(Qt::WindowModal); startupWidget->setWindowTitle(i18n("Create new document")); KisConfig cfg(true); int w = cfg.defImageWidth(); int h = cfg.defImageHeight(); const double resolution = cfg.defImageResolution(); const QString colorModel = cfg.defColorModel(); const QString colorDepth = cfg.defaultColorDepth(); const QString colorProfile = cfg.defColorProfile(); CustomDocumentWidgetItem item; item.widget = new KisCustomImageWidget(startupWidget, w, h, resolution, colorModel, colorDepth, colorProfile, i18n("Unnamed")); item.icon = "document-new"; startupWidget->addCustomDocumentWidget(item.widget, item.title, item.icon); QSize sz = KisClipboard::instance()->clipSize(); if (sz.isValid() && sz.width() != 0 && sz.height() != 0) { w = sz.width(); h = sz.height(); } item.widget = new KisImageFromClipboard(startupWidget, w, h, resolution, colorModel, colorDepth, colorProfile, i18n("Unnamed")); item.title = i18n("Create from Clipboard"); item.icon = "tab-new"; startupWidget->addCustomDocumentWidget(item.widget, item.title, item.icon); // calls deleteLater connect(startupWidget, SIGNAL(documentSelected(KisDocument*)), KisPart::instance(), SLOT(startCustomDocument(KisDocument*))); // calls deleteLater connect(startupWidget, SIGNAL(openTemplate(QUrl)), KisPart::instance(), SLOT(openTemplate(QUrl))); startupWidget->exec(); // Cancel calls deleteLater... } void KisMainWindow::slotImportFile() { dbgUI << "slotImportFile()"; slotFileOpen(true); } void KisMainWindow::slotFileOpen(bool isImporting) { QStringList urls = showOpenFileDialog(isImporting); if (urls.isEmpty()) return; Q_FOREACH (const QString& url, urls) { if (!url.isEmpty()) { OpenFlags flags = isImporting ? Import : None; bool res = openDocument(QUrl::fromLocalFile(url), flags); if (!res) { warnKrita << "Loading" << url << "failed"; } } } } void KisMainWindow::slotFileOpenRecent(const QUrl &url) { (void) openDocument(QUrl::fromLocalFile(url.toLocalFile()), None); } void KisMainWindow::slotFileSave() { if (saveDocument(d->activeView->document(), false, false)) { emit documentSaved(); } } void KisMainWindow::slotFileSaveAs() { if (saveDocument(d->activeView->document(), true, false)) { emit documentSaved(); } } void KisMainWindow::slotExportFile() { if (saveDocument(d->activeView->document(), true, true)) { emit documentSaved(); } } void KisMainWindow::slotShowSessionManager() { KisPart::instance()->showSessionManager(); } KoCanvasResourceProvider *KisMainWindow::resourceManager() const { return d->viewManager->resourceProvider()->resourceManager(); } int KisMainWindow::viewCount() const { return d->mdiArea->subWindowList().size(); } const KConfigGroup &KisMainWindow::windowStateConfig() const { return d->windowStateConfig; } void KisMainWindow::saveWindowState(bool restoreNormalState) { if (restoreNormalState) { QAction *showCanvasOnly = d->viewManager->actionCollection()->action("view_show_canvas_only"); if (showCanvasOnly && showCanvasOnly->isChecked()) { showCanvasOnly->setChecked(false); } d->windowStateConfig.writeEntry("ko_geometry", saveGeometry().toBase64()); d->windowStateConfig.writeEntry("State", saveState().toBase64()); if (!d->dockerStateBeforeHiding.isEmpty()) { restoreState(d->dockerStateBeforeHiding); } statusBar()->setVisible(true); menuBar()->setVisible(true); saveWindowSettings(); } else { saveMainWindowSettings(d->windowStateConfig); } } bool KisMainWindow::restoreWorkspaceState(const QByteArray &state) { QByteArray oldState = saveState(); // needed because otherwise the layout isn't correctly restored in some situations Q_FOREACH (QDockWidget *dock, dockWidgets()) { dock->toggleViewAction()->setEnabled(true); dock->hide(); } bool success = KXmlGuiWindow::restoreState(state); if (!success) { KXmlGuiWindow::restoreState(oldState); return false; } return success; } bool KisMainWindow::restoreWorkspace(KisWorkspaceResourceSP workspace) { bool success = restoreWorkspaceState(workspace->dockerState()); if (activeKisView()) { activeKisView()->resourceProvider()->notifyLoadingWorkspace(workspace); } return success; } QByteArray KisMainWindow::borrowWorkspace(KisMainWindow *other) { QByteArray currentWorkspace = saveState(); if (!d->workspaceBorrowedBy.isNull()) { if (other->id() == d->workspaceBorrowedBy) { // We're swapping our original workspace back d->workspaceBorrowedBy = QUuid(); return currentWorkspace; } else { // Get our original workspace back before swapping with a third window KisMainWindow *borrower = KisPart::instance()->windowById(d->workspaceBorrowedBy); if (borrower) { QByteArray originalLayout = borrower->borrowWorkspace(this); borrower->restoreWorkspaceState(currentWorkspace); d->workspaceBorrowedBy = other->id(); return originalLayout; } } } d->workspaceBorrowedBy = other->id(); return currentWorkspace; } void KisMainWindow::swapWorkspaces(KisMainWindow *a, KisMainWindow *b) { QByteArray workspaceA = a->borrowWorkspace(b); QByteArray workspaceB = b->borrowWorkspace(a); a->restoreWorkspaceState(workspaceB); b->restoreWorkspaceState(workspaceA); } KisViewManager *KisMainWindow::viewManager() const { return d->viewManager; } void KisMainWindow::slotDocumentInfo() { if (!d->activeView->document()) return; KoDocumentInfo *docInfo = d->activeView->document()->documentInfo(); if (!docInfo) return; KoDocumentInfoDlg *dlg = d->activeView->document()->createDocumentInfoDialog(this, docInfo); if (dlg->exec()) { if (dlg->isDocumentSaved()) { d->activeView->document()->setModified(false); } else { d->activeView->document()->setModified(true); } d->activeView->document()->setTitleModified(); } delete dlg; } bool KisMainWindow::slotFileCloseAll() { Q_FOREACH (QMdiSubWindow *subwin, d->mdiArea->subWindowList()) { if (subwin) { if(!subwin->close()) return false; } } updateCaption(); return true; } void KisMainWindow::slotFileQuit() { KisPart::instance()->closeSession(); } void KisMainWindow::slotFilePrint() { if (!activeView()) return; KisPrintJob *printJob = activeView()->createPrintJob(); if (printJob == 0) return; applyDefaultSettings(printJob->printer()); QPrintDialog *printDialog = activeView()->createPrintDialog( printJob, this ); if (printDialog && printDialog->exec() == QDialog::Accepted) { printJob->printer().setPageMargins(0.0, 0.0, 0.0, 0.0, QPrinter::Point); printJob->printer().setPaperSize(QSizeF(activeView()->image()->width() / (72.0 * activeView()->image()->xRes()), activeView()->image()->height()/ (72.0 * activeView()->image()->yRes())), QPrinter::Inch); printJob->startPrinting(KisPrintJob::DeleteWhenDone); } else { delete printJob; } delete printDialog; } void KisMainWindow::slotFilePrintPreview() { if (!activeView()) return; KisPrintJob *printJob = activeView()->createPrintJob(); if (printJob == 0) return; /* Sets the startPrinting() slot to be blocking. The Qt print-preview dialog requires the printing to be completely blocking and only return when the full document has been printed. By default the KisPrintingDialog is non-blocking and multithreading, setting blocking to true will allow it to be used in the preview dialog */ printJob->setProperty("blocking", true); QPrintPreviewDialog *preview = new QPrintPreviewDialog(&printJob->printer(), this); printJob->setParent(preview); // will take care of deleting the job connect(preview, SIGNAL(paintRequested(QPrinter*)), printJob, SLOT(startPrinting())); preview->exec(); delete preview; } KisPrintJob* KisMainWindow::exportToPdf(QString pdfFileName) { if (!activeView()) return 0; if (!activeView()->document()) return 0; KoPageLayout pageLayout; pageLayout.width = 0; pageLayout.height = 0; pageLayout.topMargin = 0; pageLayout.bottomMargin = 0; pageLayout.leftMargin = 0; pageLayout.rightMargin = 0; if (pdfFileName.isEmpty()) { KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs"); QString defaultDir = group.readEntry("SavePdfDialog"); if (defaultDir.isEmpty()) defaultDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); QUrl startUrl = QUrl::fromLocalFile(defaultDir); KisDocument* pDoc = d->activeView->document(); /** if document has a file name, take file name and replace extension with .pdf */ if (pDoc && pDoc->url().isValid()) { startUrl = pDoc->url(); QString fileName = startUrl.toLocalFile(); fileName = fileName.replace( QRegExp( "\\.\\w{2,5}$", Qt::CaseInsensitive ), ".pdf" ); startUrl = startUrl.adjusted(QUrl::RemoveFilename); startUrl.setPath(startUrl.path() + fileName ); } QPointer layoutDlg(new KoPageLayoutDialog(this, pageLayout)); layoutDlg->setWindowModality(Qt::WindowModal); if (layoutDlg->exec() != QDialog::Accepted || !layoutDlg) { delete layoutDlg; return 0; } pageLayout = layoutDlg->pageLayout(); delete layoutDlg; KoFileDialog dialog(this, KoFileDialog::SaveFile, "OpenDocument"); dialog.setCaption(i18n("Export as PDF")); dialog.setDefaultDir(startUrl.toLocalFile()); dialog.setMimeTypeFilters(QStringList() << "application/pdf"); QUrl url = QUrl::fromUserInput(dialog.filename()); pdfFileName = url.toLocalFile(); if (pdfFileName.isEmpty()) return 0; } KisPrintJob *printJob = activeView()->createPrintJob(); if (printJob == 0) return 0; if (isHidden()) { printJob->setProperty("noprogressdialog", true); } applyDefaultSettings(printJob->printer()); // TODO for remote files we have to first save locally and then upload. printJob->printer().setOutputFileName(pdfFileName); printJob->printer().setDocName(pdfFileName); printJob->printer().setColorMode(QPrinter::Color); if (pageLayout.format == KoPageFormat::CustomSize) { printJob->printer().setPaperSize(QSizeF(pageLayout.width, pageLayout.height), QPrinter::Millimeter); } else { printJob->printer().setPaperSize(KoPageFormat::printerPageSize(pageLayout.format)); } printJob->printer().setPageMargins(pageLayout.leftMargin, pageLayout.topMargin, pageLayout.rightMargin, pageLayout.bottomMargin, QPrinter::Millimeter); switch (pageLayout.orientation) { case KoPageFormat::Portrait: printJob->printer().setOrientation(QPrinter::Portrait); break; case KoPageFormat::Landscape: printJob->printer().setOrientation(QPrinter::Landscape); break; } //before printing check if the printer can handle printing if (!printJob->canPrint()) { QMessageBox::critical(this, i18nc("@title:window", "Krita"), i18n("Cannot export to the specified file")); } printJob->startPrinting(KisPrintJob::DeleteWhenDone); return printJob; } void KisMainWindow::importAnimation() { if (!activeView()) return; KisDocument *document = activeView()->document(); if (!document) return; KisDlgImportImageSequence dlg(this, document); if (dlg.exec() == QDialog::Accepted) { QStringList files = dlg.files(); int firstFrame = dlg.firstFrame(); int step = dlg.step(); KoUpdaterPtr updater = !document->fileBatchMode() ? viewManager()->createUnthreadedUpdater(i18n("Import frames")) : 0; KisAnimationImporter importer(document->image(), updater); KisImportExportFilter::ConversionStatus status = importer.import(files, firstFrame, step); if (status != KisImportExportFilter::OK && status != KisImportExportFilter::InternalError) { QString msg = KisImportExportFilter::conversionStatusString(status); if (!msg.isEmpty()) QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not finish import animation:\n%1", msg)); } activeView()->canvasBase()->refetchDataFromImage(); } } void KisMainWindow::slotConfigureToolbars() { saveWindowState(); KEditToolBar edit(factory(), this); connect(&edit, SIGNAL(newToolBarConfig()), this, SLOT(slotNewToolbarConfig())); (void) edit.exec(); applyToolBarLayout(); } void KisMainWindow::slotNewToolbarConfig() { applyMainWindowSettings(d->windowStateConfig); KXMLGUIFactory *factory = guiFactory(); Q_UNUSED(factory); // Check if there's an active view if (!d->activeView) return; plugActionList("toolbarlist", d->toolbarList); applyToolBarLayout(); } void KisMainWindow::slotToolbarToggled(bool toggle) { //dbgUI <<"KisMainWindow::slotToolbarToggled" << sender()->name() <<" toggle=" << true; // The action (sender) and the toolbar have the same name KToolBar * bar = toolBar(sender()->objectName()); if (bar) { if (toggle) { bar->show(); } else { bar->hide(); } if (d->activeView && d->activeView->document()) { saveWindowState(); } } else warnUI << "slotToolbarToggled : Toolbar " << sender()->objectName() << " not found!"; } void KisMainWindow::viewFullscreen(bool fullScreen) { KisConfig cfg(false); cfg.setFullscreenMode(fullScreen); if (fullScreen) { setWindowState(windowState() | Qt::WindowFullScreen); // set } else { setWindowState(windowState() & ~Qt::WindowFullScreen); // reset } } void KisMainWindow::setMaxRecentItems(uint _number) { d->recentFiles->setMaxItems(_number); } void KisMainWindow::slotReloadFile() { KisDocument* document = d->activeView->document(); if (!document || document->url().isEmpty()) return; if (document->isModified()) { bool ok = QMessageBox::question(this, i18nc("@title:window", "Krita"), i18n("You will lose all changes made since your last save\n" "Do you want to continue?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes; if (!ok) return; } QUrl url = document->url(); saveWindowSettings(); if (!document->reload()) { QMessageBox::critical(this, i18nc("@title:window", "Krita"), i18n("Error: Could not reload this document")); } return; } QDockWidget* KisMainWindow::createDockWidget(KoDockFactoryBase* factory) { QDockWidget* dockWidget = 0; bool lockAllDockers = KisConfig(true).readEntry("LockAllDockerPanels", false); if (!d->dockWidgetsMap.contains(factory->id())) { dockWidget = factory->createDockWidget(); // It is quite possible that a dock factory cannot create the dock; don't // do anything in that case. if (!dockWidget) { warnKrita << "Could not create docker for" << factory->id(); return 0; } dockWidget->setFont(KoDockRegistry::dockFont()); dockWidget->setObjectName(factory->id()); dockWidget->setParent(this); if (lockAllDockers) { if (dockWidget->titleBarWidget()) { dockWidget->titleBarWidget()->setVisible(false); } dockWidget->setFeatures(QDockWidget::NoDockWidgetFeatures); } if (dockWidget->widget() && dockWidget->widget()->layout()) dockWidget->widget()->layout()->setContentsMargins(1, 1, 1, 1); Qt::DockWidgetArea side = Qt::RightDockWidgetArea; bool visible = true; switch (factory->defaultDockPosition()) { case KoDockFactoryBase::DockTornOff: dockWidget->setFloating(true); // position nicely? break; case KoDockFactoryBase::DockTop: side = Qt::TopDockWidgetArea; break; case KoDockFactoryBase::DockLeft: side = Qt::LeftDockWidgetArea; break; case KoDockFactoryBase::DockBottom: side = Qt::BottomDockWidgetArea; break; case KoDockFactoryBase::DockRight: side = Qt::RightDockWidgetArea; break; case KoDockFactoryBase::DockMinimized: default: side = Qt::RightDockWidgetArea; visible = false; } KConfigGroup group = d->windowStateConfig.group("DockWidget " + factory->id()); side = static_cast(group.readEntry("DockArea", static_cast(side))); if (side == Qt::NoDockWidgetArea) side = Qt::RightDockWidgetArea; addDockWidget(side, dockWidget); if (!visible) { dockWidget->hide(); } d->dockWidgetsMap.insert(factory->id(), dockWidget); } else { dockWidget = d->dockWidgetsMap[factory->id()]; } #ifdef Q_OS_OSX dockWidget->setAttribute(Qt::WA_MacSmallSize, true); #endif dockWidget->setFont(KoDockRegistry::dockFont()); connect(dockWidget, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(forceDockTabFonts())); return dockWidget; } void KisMainWindow::forceDockTabFonts() { Q_FOREACH (QObject *child, children()) { if (child->inherits("QTabBar")) { ((QTabBar *)child)->setFont(KoDockRegistry::dockFont()); } } } QList KisMainWindow::dockWidgets() const { return d->dockWidgetsMap.values(); } QDockWidget* KisMainWindow::dockWidget(const QString &id) { if (!d->dockWidgetsMap.contains(id)) return 0; return d->dockWidgetsMap[id]; } QList KisMainWindow::canvasObservers() const { QList observers; Q_FOREACH (QDockWidget *docker, dockWidgets()) { KoCanvasObserverBase *observer = dynamic_cast(docker); if (observer) { observers << observer; } else { warnKrita << docker << "is not a canvas observer"; } } return observers; } void KisMainWindow::toggleDockersVisibility(bool visible) { if (!visible) { d->dockerStateBeforeHiding = saveState(); Q_FOREACH (QObject* widget, children()) { if (widget->inherits("QDockWidget")) { QDockWidget* dw = static_cast(widget); if (dw->isVisible()) { dw->hide(); } } } } else { restoreState(d->dockerStateBeforeHiding); } } void KisMainWindow::slotDocumentTitleModified() { updateCaption(); updateReloadFileAction(d->activeView ? d->activeView->document() : 0); } void KisMainWindow::subWindowActivated() { bool enabled = (activeKisView() != 0); d->mdiCascade->setEnabled(enabled); d->mdiNextWindow->setEnabled(enabled); d->mdiPreviousWindow->setEnabled(enabled); d->mdiTile->setEnabled(enabled); d->close->setEnabled(enabled); d->closeAll->setEnabled(enabled); setActiveSubWindow(d->mdiArea->activeSubWindow()); Q_FOREACH (QToolBar *tb, toolBars()) { if (tb->objectName() == "BrushesAndStuff") { tb->setEnabled(enabled); } } /** * Qt has a weirdness, it has hardcoded shortcuts added to an action * in the window menu. We need to reset the shortcuts for that menu * to nothing, otherwise the shortcuts cannot be made configurable. * * See: https://bugs.kde.org/show_bug.cgi?id=352205 * https://bugs.kde.org/show_bug.cgi?id=375524 * https://bugs.kde.org/show_bug.cgi?id=398729 */ QMdiSubWindow *subWindow = d->mdiArea->currentSubWindow(); if (subWindow) { QMenu *menu = subWindow->systemMenu(); if (menu && menu->actions().size() == 8) { Q_FOREACH (QAction *action, menu->actions()) { action->setShortcut(QKeySequence()); } menu->actions().last()->deleteLater(); } } updateCaption(); d->actionManager()->updateGUI(); } void KisMainWindow::windowFocused() { /** * Notify selection manager so that it could update selection mask overlay */ if (viewManager() && viewManager()->selectionManager()) { viewManager()->selectionManager()->selectionChanged(); } KisPart *kisPart = KisPart::instance(); KisWindowLayoutManager *layoutManager = KisWindowLayoutManager::instance(); if (!layoutManager->primaryWorkspaceFollowsFocus()) return; QUuid primary = layoutManager->primaryWindowId(); if (primary.isNull()) return; if (d->id == primary) { if (!d->workspaceBorrowedBy.isNull()) { KisMainWindow *borrower = kisPart->windowById(d->workspaceBorrowedBy); if (!borrower) return; swapWorkspaces(this, borrower); } } else { if (d->workspaceBorrowedBy == primary) return; KisMainWindow *primaryWindow = kisPart->windowById(primary); if (!primaryWindow) return; swapWorkspaces(this, primaryWindow); } } void KisMainWindow::updateWindowMenu() { QMenu *menu = d->windowMenu->menu(); menu->clear(); menu->addAction(d->newWindow); menu->addAction(d->documentMenu); QMenu *docMenu = d->documentMenu->menu(); docMenu->clear(); Q_FOREACH (QPointer doc, KisPart::instance()->documents()) { if (doc) { QString title = doc->url().toDisplayString(); if (title.isEmpty() && doc->image()) { title = doc->image()->objectName(); } QAction *action = docMenu->addAction(title); action->setIcon(qApp->windowIcon()); connect(action, SIGNAL(triggered()), d->documentMapper, SLOT(map())); d->documentMapper->setMapping(action, doc); } } menu->addAction(d->workspaceMenu); QMenu *workspaceMenu = d->workspaceMenu->menu(); workspaceMenu->clear(); auto workspaces = KisResourceServerProvider::instance()->workspaceServer()->resources(); auto m_this = this; for (auto &w : workspaces) { auto action = workspaceMenu->addAction(w->name()); connect(action, &QAction::triggered, this, [=]() { m_this->restoreWorkspace(w); }); } workspaceMenu->addSeparator(); connect(workspaceMenu->addAction(i18nc("@action:inmenu", "&Import Workspace...")), &QAction::triggered, this, [&]() { QString extensions = d->workspacemodel->extensions(); QStringList mimeTypes; for(const QString &suffix : extensions.split(":")) { mimeTypes << KisMimeDatabase::mimeTypeForSuffix(suffix); } KoFileDialog dialog(0, KoFileDialog::OpenFile, "OpenDocument"); dialog.setMimeTypeFilters(mimeTypes); dialog.setCaption(i18nc("@title:window", "Choose File to Add")); QString filename = dialog.filename(); d->workspacemodel->importResourceFile(filename); }); connect(workspaceMenu->addAction(i18nc("@action:inmenu", "&New Workspace...")), &QAction::triggered, [=]() { QString name = QInputDialog::getText(this, i18nc("@title:window", "New Workspace..."), i18nc("@label:textbox", "Name:")); if (name.isEmpty()) return; auto rserver = KisResourceServerProvider::instance()->workspaceServer(); KisWorkspaceResourceSP workspace(new KisWorkspaceResource("")); workspace->setDockerState(m_this->saveState()); d->viewManager->resourceProvider()->notifySavingWorkspace(workspace); workspace->setValid(true); QString saveLocation = rserver->saveLocation(); bool newName = false; if(name.isEmpty()) { newName = true; name = i18n("Workspace"); } QFileInfo fileInfo(saveLocation + name + workspace->defaultFileExtension()); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(saveLocation + name + QString("%1").arg(i) + workspace->defaultFileExtension()); i++; } workspace->setFilename(fileInfo.filePath()); if(newName) { name = i18n("Workspace %1", i); } workspace->setName(name); rserver->addResource(workspace); }); // TODO: What to do about delete? // workspaceMenu->addAction(i18nc("@action:inmenu", "&Delete Workspace...")); menu->addSeparator(); menu->addAction(d->close); menu->addAction(d->closeAll); if (d->mdiArea->viewMode() == QMdiArea::SubWindowView) { menu->addSeparator(); menu->addAction(d->mdiTile); menu->addAction(d->mdiCascade); } menu->addSeparator(); menu->addAction(d->mdiNextWindow); menu->addAction(d->mdiPreviousWindow); menu->addSeparator(); QList windows = d->mdiArea->subWindowList(); for (int i = 0; i < windows.size(); ++i) { QPointerchild = qobject_cast(windows.at(i)->widget()); if (child && child->document()) { QString text; if (i < 9) { text = i18n("&%1 %2", i + 1, child->document()->url().toDisplayString()); } else { text = i18n("%1 %2", i + 1, child->document()->url().toDisplayString()); } QAction *action = menu->addAction(text); action->setIcon(qApp->windowIcon()); action->setCheckable(true); action->setChecked(child == activeKisView()); connect(action, SIGNAL(triggered()), d->windowMapper, SLOT(map())); d->windowMapper->setMapping(action, windows.at(i)); } } bool showMdiArea = windows.count( ) > 0; if (!showMdiArea) { showWelcomeScreen(true); // see workaround in function in header // keep the recent file list updated when going back to welcome screen reloadRecentFileList(); d->welcomePage->populateRecentDocuments(); } // enable/disable the toolbox docker if there are no documents open Q_FOREACH (QObject* widget, children()) { if (widget->inherits("QDockWidget")) { QDockWidget* dw = static_cast(widget); if ( dw->objectName() == "ToolBox") { dw->setEnabled(showMdiArea); } } } updateCaption(); } void KisMainWindow::setActiveSubWindow(QWidget *window) { if (!window) return; QMdiSubWindow *subwin = qobject_cast(window); //dbgKrita << "setActiveSubWindow();" << subwin << d->activeSubWindow; if (subwin && subwin != d->activeSubWindow) { KisView *view = qobject_cast(subwin->widget()); //dbgKrita << "\t" << view << activeView(); if (view && view != activeView()) { d->mdiArea->setActiveSubWindow(subwin); setActiveView(view); } d->activeSubWindow = subwin; } updateWindowMenu(); d->actionManager()->updateGUI(); } void KisMainWindow::configChanged() { KisConfig cfg(true); QMdiArea::ViewMode viewMode = (QMdiArea::ViewMode)cfg.readEntry("mdi_viewmode", (int)QMdiArea::TabbedView); d->mdiArea->setViewMode(viewMode); Q_FOREACH (QMdiSubWindow *subwin, d->mdiArea->subWindowList()) { subwin->setOption(QMdiSubWindow::RubberBandMove, cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); subwin->setOption(QMdiSubWindow::RubberBandResize, cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); /** * Dirty workaround for a bug in Qt (checked on Qt 5.6.1): * * If you make a window "Show on top" and then switch to the tabbed mode * the window will contiue to be painted in its initial "mid-screen" * position. It will persist here until you explicitly switch to its tab. */ if (viewMode == QMdiArea::TabbedView) { Qt::WindowFlags oldFlags = subwin->windowFlags(); Qt::WindowFlags flags = oldFlags; flags &= ~Qt::WindowStaysOnTopHint; flags &= ~Qt::WindowStaysOnBottomHint; if (flags != oldFlags) { subwin->setWindowFlags(flags); subwin->showMaximized(); } } } KConfigGroup group( KSharedConfig::openConfig(), "theme"); d->themeManager->setCurrentTheme(group.readEntry("Theme", "Krita dark")); d->actionManager()->updateGUI(); QBrush brush(cfg.getMDIBackgroundColor()); d->mdiArea->setBackground(brush); QString backgroundImage = cfg.getMDIBackgroundImage(); if (backgroundImage != "") { QImage image(backgroundImage); QBrush brush(image); d->mdiArea->setBackground(brush); } d->mdiArea->update(); } KisView* KisMainWindow::newView(QObject *document) { KisDocument *doc = qobject_cast(document); KisView *view = addViewAndNotifyLoadingCompleted(doc); d->actionManager()->updateGUI(); return view; } void KisMainWindow::newWindow() { KisMainWindow *mainWindow = KisPart::instance()->createMainWindow(); mainWindow->initializeGeometry(); mainWindow->show(); } void KisMainWindow::closeCurrentWindow() { if (d->mdiArea->currentSubWindow()) { d->mdiArea->currentSubWindow()->close(); d->actionManager()->updateGUI(); } } void KisMainWindow::checkSanity() { // print error if the lcms engine is not available if (!KoColorSpaceEngineRegistry::instance()->contains("icc")) { // need to wait 1 event since exiting here would not work. m_errorMessage = i18n("The Krita LittleCMS color management plugin is not installed. Krita will quit now."); m_dieOnError = true; QTimer::singleShot(0, this, SLOT(showErrorAndDie())); return; } KisPaintOpPresetResourceServer * rserver = KisResourceServerProvider::instance()->paintOpPresetServer(); if (rserver->resources().isEmpty()) { m_errorMessage = i18n("Krita cannot find any brush presets! Krita will quit now."); m_dieOnError = true; QTimer::singleShot(0, this, SLOT(showErrorAndDie())); return; } } void KisMainWindow::showErrorAndDie() { QMessageBox::critical(0, i18nc("@title:window", "Installation error"), m_errorMessage); if (m_dieOnError) { exit(10); } } void KisMainWindow::showAboutApplication() { KisAboutApplication dlg(this); dlg.exec(); } QPointer KisMainWindow::activeKisView() { if (!d->mdiArea) return 0; QMdiSubWindow *activeSubWindow = d->mdiArea->activeSubWindow(); //dbgKrita << "activeKisView" << activeSubWindow; if (!activeSubWindow) return 0; return qobject_cast(activeSubWindow->widget()); } void KisMainWindow::newOptionWidgets(KoCanvasController *controller, const QList > &optionWidgetList) { KIS_ASSERT_RECOVER_NOOP(controller == KoToolManager::instance()->activeCanvasController()); bool isOurOwnView = false; Q_FOREACH (QPointer view, KisPart::instance()->views()) { if (view && view->canvasController() == controller) { isOurOwnView = view->mainWindow() == this; } } if (!isOurOwnView) return; Q_FOREACH (QWidget *w, optionWidgetList) { #ifdef Q_OS_OSX w->setAttribute(Qt::WA_MacSmallSize, true); #endif w->setFont(KoDockRegistry::dockFont()); } if (d->toolOptionsDocker) { d->toolOptionsDocker->setOptionWidgets(optionWidgetList); } else { d->viewManager->paintOpBox()->newOptionWidgets(optionWidgetList); } } void KisMainWindow::applyDefaultSettings(QPrinter &printer) { if (!d->activeView) return; QString title = d->activeView->document()->documentInfo()->aboutInfo("title"); if (title.isEmpty()) { QFileInfo info(d->activeView->document()->url().fileName()); title = info.baseName(); } if (title.isEmpty()) { // #139905 title = i18n("%1 unsaved document (%2)", qApp->applicationDisplayName(), QLocale().toString(QDate::currentDate(), QLocale::ShortFormat)); } printer.setDocName(title); } void KisMainWindow::createActions() { KisActionManager *actionManager = d->actionManager(); actionManager->createStandardAction(KStandardAction::New, this, SLOT(slotFileNew())); actionManager->createStandardAction(KStandardAction::Open, this, SLOT(slotFileOpen())); actionManager->createStandardAction(KStandardAction::Quit, this, SLOT(slotFileQuit())); actionManager->createStandardAction(KStandardAction::ConfigureToolbars, this, SLOT(slotConfigureToolbars())); d->fullScreenMode = actionManager->createStandardAction(KStandardAction::FullScreen, this, SLOT(viewFullscreen(bool))); d->recentFiles = KStandardAction::openRecent(this, SLOT(slotFileOpenRecent(QUrl)), actionCollection()); connect(d->recentFiles, SIGNAL(recentListCleared()), this, SLOT(saveRecentFiles())); KSharedConfigPtr configPtr = KSharedConfig::openConfig(); d->recentFiles->loadEntries(configPtr->group("RecentFiles")); d->saveAction = actionManager->createStandardAction(KStandardAction::Save, this, SLOT(slotFileSave())); d->saveAction->setActivationFlags(KisAction::ACTIVE_IMAGE); d->saveActionAs = actionManager->createStandardAction(KStandardAction::SaveAs, this, SLOT(slotFileSaveAs())); d->saveActionAs->setActivationFlags(KisAction::ACTIVE_IMAGE); // d->printAction = actionManager->createStandardAction(KStandardAction::Print, this, SLOT(slotFilePrint())); // d->printAction->setActivationFlags(KisAction::ACTIVE_IMAGE); // d->printActionPreview = actionManager->createStandardAction(KStandardAction::PrintPreview, this, SLOT(slotFilePrintPreview())); // d->printActionPreview->setActivationFlags(KisAction::ACTIVE_IMAGE); d->undo = actionManager->createStandardAction(KStandardAction::Undo, this, SLOT(undo())); d->undo->setActivationFlags(KisAction::ACTIVE_IMAGE); d->redo = actionManager->createStandardAction(KStandardAction::Redo, this, SLOT(redo())); d->redo->setActivationFlags(KisAction::ACTIVE_IMAGE); d->undoActionsUpdateManager.reset(new KisUndoActionsUpdateManager(d->undo, d->redo)); d->undoActionsUpdateManager->setCurrentDocument(d->activeView ? d->activeView->document() : 0); // d->exportPdf = actionManager->createAction("file_export_pdf"); // connect(d->exportPdf, SIGNAL(triggered()), this, SLOT(exportToPdf())); d->importAnimation = actionManager->createAction("file_import_animation"); connect(d->importAnimation, SIGNAL(triggered()), this, SLOT(importAnimation())); d->closeAll = actionManager->createAction("file_close_all"); connect(d->closeAll, SIGNAL(triggered()), this, SLOT(slotFileCloseAll())); // d->reloadFile = actionManager->createAction("file_reload_file"); // d->reloadFile->setActivationFlags(KisAction::CURRENT_IMAGE_MODIFIED); // connect(d->reloadFile, SIGNAL(triggered(bool)), this, SLOT(slotReloadFile())); d->importFile = actionManager->createAction("file_import_file"); connect(d->importFile, SIGNAL(triggered(bool)), this, SLOT(slotImportFile())); d->exportFile = actionManager->createAction("file_export_file"); connect(d->exportFile, SIGNAL(triggered(bool)), this, SLOT(slotExportFile())); /* The following entry opens the document information dialog. Since the action is named so it intends to show data this entry should not have a trailing ellipses (...). */ d->showDocumentInfo = actionManager->createAction("file_documentinfo"); connect(d->showDocumentInfo, SIGNAL(triggered(bool)), this, SLOT(slotDocumentInfo())); d->themeManager->setThemeMenuAction(new KActionMenu(i18nc("@action:inmenu", "&Themes"), this)); d->themeManager->registerThemeActions(actionCollection()); connect(d->themeManager, SIGNAL(signalThemeChanged()), this, SLOT(slotThemeChanged())); connect(d->themeManager, SIGNAL(signalThemeChanged()), d->welcomePage, SLOT(slotUpdateThemeColors())); d->toggleDockers = actionManager->createAction("view_toggledockers"); KisConfig(true).showDockers(true); d->toggleDockers->setChecked(true); connect(d->toggleDockers, SIGNAL(toggled(bool)), SLOT(toggleDockersVisibility(bool))); actionCollection()->addAction("settings_dockers_menu", d->dockWidgetMenu); actionCollection()->addAction("window", d->windowMenu); d->mdiCascade = actionManager->createAction("windows_cascade"); connect(d->mdiCascade, SIGNAL(triggered()), d->mdiArea, SLOT(cascadeSubWindows())); d->mdiTile = actionManager->createAction("windows_tile"); connect(d->mdiTile, SIGNAL(triggered()), d->mdiArea, SLOT(tileSubWindows())); d->mdiNextWindow = actionManager->createAction("windows_next"); connect(d->mdiNextWindow, SIGNAL(triggered()), d->mdiArea, SLOT(activateNextSubWindow())); d->mdiPreviousWindow = actionManager->createAction("windows_previous"); connect(d->mdiPreviousWindow, SIGNAL(triggered()), d->mdiArea, SLOT(activatePreviousSubWindow())); d->newWindow = actionManager->createAction("view_newwindow"); connect(d->newWindow, SIGNAL(triggered(bool)), this, SLOT(newWindow())); d->close = actionManager->createStandardAction(KStandardAction::Close, this, SLOT(closeCurrentWindow())); d->showSessionManager = actionManager->createAction("file_sessions"); connect(d->showSessionManager, SIGNAL(triggered(bool)), this, SLOT(slotShowSessionManager())); actionManager->createStandardAction(KStandardAction::Preferences, this, SLOT(slotPreferences())); for (int i = 0; i < 2; i++) { d->expandingSpacers[i] = new KisAction(i18n("Expanding Spacer")); d->expandingSpacers[i]->setDefaultWidget(new QWidget(this)); d->expandingSpacers[i]->defaultWidget()->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); actionManager->addAction(QString("expanding_spacer_%1").arg(i), d->expandingSpacers[i]); } } void KisMainWindow::applyToolBarLayout() { const bool isPlastiqueStyle = style()->objectName() == "plastique"; Q_FOREACH (KToolBar *toolBar, toolBars()) { toolBar->layout()->setSpacing(4); if (isPlastiqueStyle) { toolBar->setContentsMargins(0, 0, 0, 2); } //Hide text for buttons with an icon in the toolbar Q_FOREACH (QAction *ac, toolBar->actions()){ if (ac->icon().pixmap(QSize(1,1)).isNull() == false){ ac->setPriority(QAction::LowPriority); }else { ac->setIcon(QIcon()); } } } } void KisMainWindow::initializeGeometry() { // if the user didn's specify the geometry on the command line (does anyone do that still?), // we first figure out some good default size and restore the x,y position. See bug 285804Z. KConfigGroup cfg = d->windowStateConfig; QByteArray geom = QByteArray::fromBase64(cfg.readEntry("ko_geometry", QByteArray())); if (!restoreGeometry(geom)) { const int scnum = QApplication::desktop()->screenNumber(parentWidget()); QRect desk = QApplication::desktop()->availableGeometry(scnum); // if the desktop is virtual then use virtual screen size if (QApplication::desktop()->isVirtualDesktop()) { desk = QApplication::desktop()->availableGeometry(QApplication::desktop()->screen(scnum)); } quint32 x = desk.x(); quint32 y = desk.y(); quint32 w = 0; quint32 h = 0; // Default size -- maximize on small screens, something useful on big screens const int deskWidth = desk.width(); if (deskWidth > 1024) { // a nice width, and slightly less than total available // height to compensate for the window decs w = (deskWidth / 3) * 2; h = (desk.height() / 3) * 2; } else { w = desk.width(); h = desk.height(); } x += (desk.width() - w) / 2; y += (desk.height() - h) / 2; move(x,y); setGeometry(geometry().x(), geometry().y(), w, h); } d->fullScreenMode->setChecked(isFullScreen()); } void KisMainWindow::showManual() { QDesktopServices::openUrl(QUrl("https://docs.krita.org")); } void KisMainWindow::moveEvent(QMoveEvent *e) { /** * For checking if the display number has changed or not we should always use * positional overload, not using QWidget overload. Otherwise we might get * inconsistency, because screenNumber(widget) can return -1, but screenNumber(pos) * will always return the nearest screen. */ const int oldScreen = qApp->desktop()->screenNumber(e->oldPos()); const int newScreen = qApp->desktop()->screenNumber(e->pos()); if (oldScreen != newScreen) { emit screenChanged(); } if (d->screenConnectionsStore.isEmpty() || oldScreen != newScreen) { d->screenConnectionsStore.clear(); QScreen *newScreenObject = 0; #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) newScreenObject = qApp->screenAt(e->pos()); #else // TODO: i'm not sure if this pointer already has a correct value // by the moment we get the event. It might not work on older // versions of Qt newScreenObject = qApp->primaryScreen(); #endif if (newScreenObject) { d->screenConnectionsStore.addConnection(newScreenObject, SIGNAL(physicalDotsPerInchChanged(qreal)), this, SIGNAL(screenChanged())); } } } #include diff --git a/libs/ui/KisNodeDelegate.cpp b/libs/ui/KisNodeDelegate.cpp index c17e0771b5..06796f19a9 100644 --- a/libs/ui/KisNodeDelegate.cpp +++ b/libs/ui/KisNodeDelegate.cpp @@ -1,962 +1,1015 @@ /* Copyright (c) 2006 Gábor Lehel Copyright (c) 2008 Cyrille Berger Copyright (c) 2011 José Luis Vergara This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_config.h" #include "KisNodeDelegate.h" #include "kis_node_model.h" #include "KisNodeToolTip.h" #include "KisNodeView.h" #include "KisPart.h" #include "input/kis_input_manager.h" #include #include #include #include #include #include #include #include #include #include #include #include "kis_node_view_color_scheme.h" #include "kis_icon_utils.h" #include "kis_layer_properties_icons.h" #include "krita_utils.h" #include "kis_config_notifier.h" typedef KisBaseNode::Property* OptionalProperty; #include class KisNodeDelegate::Private { public: Private() : view(0), edit(0) { } KisNodeView *view; QPointer edit; KisNodeToolTip tip; QColor checkersColor1; QColor checkersColor2; QList rightmostProperties(const KisBaseNode::PropertyList &props) const; int numProperties(const QModelIndex &index) const; OptionalProperty findProperty(KisBaseNode::PropertyList &props, const OptionalProperty &refProp) const; OptionalProperty findVisibilityProperty(KisBaseNode::PropertyList &props) const; void toggleProperty(KisBaseNode::PropertyList &props, OptionalProperty prop, bool controlPressed, const QModelIndex &index); }; KisNodeDelegate::KisNodeDelegate(KisNodeView *view, QObject *parent) : QAbstractItemDelegate(parent) , d(new Private) { d->view = view; QApplication::instance()->installEventFilter(this); connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotConfigChanged())); slotConfigChanged(); } KisNodeDelegate::~KisNodeDelegate() { delete d; } QSize KisNodeDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { Q_UNUSED(index); KisNodeViewColorScheme scm; return QSize(option.rect.width(), scm.rowHeight()); } void KisNodeDelegate::paint(QPainter *p, const QStyleOptionViewItem &o, const QModelIndex &index) const { p->save(); { QStyleOptionViewItem option = getOptions(o, index); QStyle *style = option.widget ? option.widget->style() : QApplication::style(); style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, p, option.widget); bool shouldGrayOut = index.data(KisNodeModel::ShouldGrayOutRole).toBool(); if (shouldGrayOut) { option.state &= ~QStyle::State_Enabled; } p->setFont(option.font); - drawColorLabel(p, option, index); drawFrame(p, option, index); drawThumbnail(p, option, index); - drawText(p, option, index); + drawText(p, option, index); // BUG: Creating group moves things around (RTL-layout alignment) drawIcons(p, option, index); - drawVisibilityIconHijack(p, option, index); + drawVisibilityIconHijack(p, option, index); // TODO hide when dragging drawDecoration(p, option, index); drawExpandButton(p, option, index); drawBranch(p, option, index); drawProgressBar(p, option, index); } p->restore(); } -void KisNodeDelegate::drawBranch(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const { - Q_UNUSED(index); +void KisNodeDelegate::drawBranch(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + QModelIndex tmp = index.parent(); + + // there is no indention if we have no parent group, so don't draw a branch + if (!tmp.isValid()) return; KisNodeViewColorScheme scm; - const QPoint base = scm.relThumbnailRect().translated(option.rect.topLeft()).topLeft() - QPoint( scm.indentation(), 0); - // there is no indention if we are starting negative, so don't draw a branch - if (base.x() < 0) { - return; + int rtlNum = (option.direction == Qt::RightToLeft) ? 1 : -1; + + QRect baseRect = scm.relThumbnailRect(); + + // Move to current index + baseRect.moveTop(option.rect.topLeft().y()); + // Move to correct location. + if (option.direction == Qt::RightToLeft) { + baseRect.moveLeft(option.rect.topRight().x()); + } else { + baseRect.moveRight(option.rect.topLeft().x()); } + QPoint base = baseRect.adjusted(rtlNum*scm.indentation(), 0, + rtlNum*scm.indentation(), 0).center() + QPoint(0, scm.iconSize()/4); QPen oldPen = p->pen(); const qreal oldOpacity = p->opacity(); // remember previous opacity p->setOpacity(1.0); QColor color = scm.gridColor(option, d->view); QColor bgColor = option.state & QStyle::State_Selected ? qApp->palette().color(QPalette::Base) : qApp->palette().color(QPalette::Text); color = KritaUtils::blendColors(color, bgColor, 0.9); - // TODO: if we are a mask type, use dotted lines for the branch style // p->setPen(QPen(p->pen().color(), 2, Qt::DashLine, Qt::RoundCap, Qt::RoundJoin)); p->setPen(QPen(color, 0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); - QPoint p2 = base + QPoint(scm.iconSize() - scm.decorationMargin()*2, scm.iconSize()*0.45); - QPoint p3 = base + QPoint(scm.iconSize() - scm.decorationMargin()*2, scm.iconSize()); - QPoint p4 = base + QPoint(scm.iconSize()*1.4, scm.iconSize()); - p->drawLine(p2, p3); - p->drawLine(p3, p4); - - + QPoint p2 = base - QPoint(rtlNum*(scm.iconSize()/2), 0); + QPoint p3 = base - QPoint(0, scm.iconSize()/2); + p->drawLine(base, p2); + p->drawLine(base, p3); // draw parent lines (keep drawing until x position is less than 0 - QPoint p5 = p2 - QPoint(scm.indentation(), 0); - QPoint p6 = p3 - QPoint(scm.indentation(), 0); - - QPoint parentBase1 = p5; - QPoint parentBase2 = p6; + QPoint parentBase1 = base + QPoint(rtlNum*scm.indentation(), 0); + QPoint parentBase2 = p3 + QPoint(rtlNum*scm.indentation(), 0); // indent lines needs to be very subtle to avoid making the docker busy looking color = KritaUtils::blendColors(color, bgColor, 0.9); // makes it a little lighter than L lines p->setPen(QPen(color, 0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); - while (parentBase1.x() > scm.visibilityColumnWidth()) { - p->drawLine(parentBase1, parentBase2); - - parentBase1 = parentBase1 - QPoint(scm.indentation(), 0); - parentBase2 = parentBase2 - QPoint(scm.indentation(), 0); + if (tmp.isValid()) { + tmp = tmp.parent(); // Ignore the first group as it was already painted } + while (tmp.isValid()) { + p->drawLine(parentBase1, parentBase2); + parentBase1 += QPoint(rtlNum*scm.indentation(), 0); + parentBase2 += QPoint(rtlNum*scm.indentation(), 0); - + tmp = tmp.parent(); + } p->setPen(oldPen); p->setOpacity(oldOpacity); } void KisNodeDelegate::drawColorLabel(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const { KisNodeViewColorScheme scm; const int label = index.data(KisNodeModel::ColorLabelIndexRole).toInt(); QColor color = scm.colorLabel(label); if (color.alpha() <= 0) return; QColor bgColor = qApp->palette().color(QPalette::Base); - color = KritaUtils::blendColors(color, bgColor, 0.3); + if ((option.state & QStyle::State_MouseOver) && !(option.state & QStyle::State_Selected)) { + color = KritaUtils::blendColors(color, bgColor, 0.6); + } else { + color = KritaUtils::blendColors(color, bgColor, 0.3); + } + + QRect optionRect = option.rect.adjusted(0, 0, scm.indentation(), 0); + if (option.state & QStyle::State_Selected) { + optionRect = iconsRect(option, index); + } - const QRect rect = option.state & QStyle::State_Selected ? - iconsRect(option, index) : - option.rect.adjusted(-scm.indentation(), 0, 0, 0); + if (option.direction == Qt::RightToLeft) { + optionRect.moveLeft(option.rect.topLeft().x()); + } else { + optionRect.moveRight(option.rect.topRight().x()); + } - p->fillRect(rect, color); + p->fillRect(optionRect, color); } void KisNodeDelegate::drawFrame(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const { KisNodeViewColorScheme scm; QPen oldPen = p->pen(); p->setPen(scm.gridColor(option, d->view)); - const QPoint base = option.rect.topLeft(); + const QRect visibilityRect = visibilityClickRect(option, index); + const QRect thumbnailRect = thumbnailClickRect(option, index); + const QRect decorationRect = decorationClickRect(option, index); + const QRect iconsRectR = iconsRect(option, index); - QPoint p2 = base + QPoint(-scm.indentation() - 1, 0); - QPoint p3 = base + QPoint(2 * scm.decorationMargin() + scm.decorationSize(), 0); - QPoint p4 = base + QPoint(-1, 0); - QPoint p5(iconsRect(option, - index).left() - 1, base.y()); - QPoint p6(option.rect.right(), base.y()); - - QPoint v(0, option.rect.height()); + const float topY = thumbnailRect.topLeft().y(); + const float bottomY = thumbnailRect.bottomLeft().y(); + QPoint bottomLeftPoint; + QPoint bottomRightPoint; + if (option.direction == Qt::RightToLeft) { + bottomLeftPoint = iconsRectR.bottomLeft(); + bottomRightPoint = visibilityRect.bottomRight(); + } else { + bottomLeftPoint = visibilityRect.bottomLeft(); + bottomRightPoint = iconsRectR.bottomRight(); + } - // draw a line that goes the length of the entire frame. one for the - // top, and one for the bottom - QPoint pTopLeft(0, option.rect.topLeft().y()); - QPoint pTopRight(option.rect.bottomRight().x(),option.rect.topLeft().y() ); - p->drawLine(pTopLeft, pTopRight); + // bottom running horizontal line + p->drawLine(bottomLeftPoint.x(), bottomY, + bottomRightPoint.x(), bottomY); - QPoint pBottomLeft(0, option.rect.topLeft().y() + scm.rowHeight()); - QPoint pBottomRight(option.rect.bottomRight().x(),option.rect.topLeft().y() + scm.rowHeight() ); - p->drawLine(pBottomLeft, pBottomRight); + // visiblity icon vertical line - left + p->drawLine(visibilityRect.topLeft().x()-1, topY, + visibilityRect.bottomLeft().x()-1, bottomY); + // visiblity icon vertical line - right + p->drawLine(visibilityRect.topRight().x()+1, topY, + visibilityRect.bottomRight().x()+1, bottomY); - const bool paintForParent = - index.parent().isValid() && - !index.row(); + // thumbnail vertical line - left + p->drawLine(thumbnailRect.topLeft().x(), topY, + thumbnailRect.bottomLeft().x(), bottomY); - if (paintForParent) { - QPoint p1(-2 * scm.indentation() - 1, 0); - p1 += base; - p->drawLine(p1, p2); - } + // thumbnail vertical line - right + p->drawLine(thumbnailRect.topRight().x(), topY, + thumbnailRect.bottomRight().x(), bottomY); + // decoration vertical line - left + p->drawLine(decorationRect.topLeft().x(), topY, + decorationRect.bottomLeft().x(), bottomY); - QPoint k0(0, base.y()); - QPoint k1(1 * scm.border() + 2 * scm.visibilityMargin() + scm.visibilitySize(), base.y()); - p->drawLine(k0, k1); - p->drawLine(k0 + v, k1 + v); - p->drawLine(k0, k0 + v); - p->drawLine(k1, k1 + v); + // decoration vertical line - right + p->drawLine(decorationRect.topRight().x(), topY, + decorationRect.bottomRight().x(), bottomY); - p->drawLine(p2, p6); - p->drawLine(p2 + v, p6 + v); - p->drawLine(p2, p2 + v); - p->drawLine(p3, p3 + v); - p->drawLine(p4, p4 + v); - p->drawLine(p5, p5 + v); - p->drawLine(p6, p6 + v); + // icons' lines are drawn by drawIcons //// For debugging purposes only - //p->setPen(Qt::blue); - //KritaUtils::renderExactRect(p, iconsRect(option, index)); + p->setPen(Qt::blue); + //KritaUtils::renderExactRect(p, iconsRectR); //KritaUtils::renderExactRect(p, textRect(option, index)); - //KritaUtils::renderExactRect(p, scm.relThumbnailRect().translated(option.rect.topLeft())); + //KritaUtils::renderExactRect(p, visibilityRect); p->setPen(oldPen); } QRect KisNodeDelegate::thumbnailClickRect(const QStyleOptionViewItem &option, const QModelIndex &index) const { Q_UNUSED(index); + KisNodeViewColorScheme scm; - int steps = 0; - QModelIndex tmp = index.parent(); - while (tmp.isValid()) { - steps++; - tmp = tmp.parent(); + QRect rc = scm.relThumbnailRect(); + + // Move to current index + rc.moveTop(option.rect.topLeft().y()); + // Move to correct location. + if (option.direction == Qt::RightToLeft) { + rc.moveLeft(option.rect.topRight().x()); + } else { + rc.moveRight(option.rect.topLeft().x()); } - KisNodeViewColorScheme scm; - return QRect(scm.border() + - 2 * scm.visibilityMargin() + scm.visibilitySize() + - scm.border() + steps * scm.indentation(), - scm.border() + option.rect.top(), - 2 * scm.thumbnailMargin() + scm.thumbnailSize(), - scm.rowHeight() - scm.border()); + return rc; } void KisNodeDelegate::drawThumbnail(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const { KisNodeViewColorScheme scm; const int thumbSize = scm.thumbnailSize(); const qreal oldOpacity = p->opacity(); // remember previous opacity QImage img = index.data(int(KisNodeModel::BeginThumbnailRole) + thumbSize).value(); if (!(option.state & QStyle::State_Enabled)) { p->setOpacity(0.35); } - QRect fitRect = scm.relThumbnailRect().translated(option.rect.topLeft()); - - QPoint offset; - offset.setX((fitRect.width() - img.width()) / 2); - offset.setY((fitRect.height() - img.height()) / 2); - offset += fitRect.topLeft(); + QRect fitRect = thumbnailClickRect(option, index); + // Shrink to icon rect + fitRect = kisGrowRect(fitRect, -(scm.thumbnailMargin()+scm.border())); // paint in a checkerboard pattern behind the layer contents to represent transparent const int step = scm.thumbnailSize() / 6; QImage checkers(2 * step, 2 * step, QImage::Format_ARGB32); QPainter gc(&checkers); gc.fillRect(QRect(0, 0, step, step), d->checkersColor1); gc.fillRect(QRect(step, 0, step, step), d->checkersColor2); gc.fillRect(QRect(step, step, step, step), d->checkersColor1); gc.fillRect(QRect(0, step, step, step), d->checkersColor2); QBrush brush(checkers); - p->setBrushOrigin(offset); - p->fillRect(img.rect().translated(offset), brush); + p->fillRect(fitRect, brush); - p->drawImage(offset, img); + p->drawImage(fitRect, img); p->setOpacity(oldOpacity); // restore old opacity - QRect borderRect = kisGrowRect(img.rect(), 1).translated(offset); + QRect borderRect = kisGrowRect(fitRect, 1); KritaUtils::renderExactRect(p, borderRect, scm.gridColor(option, d->view)); } QRect KisNodeDelegate::iconsRect(const QStyleOptionViewItem &option, const QModelIndex &index) const { KisNodeViewColorScheme scm; int propCount = d->numProperties(index); const int iconsWidth = propCount * (scm.iconSize() + 2 * scm.iconMargin()) + - (propCount - 1) * scm.border(); - - const int x = option.rect.x() + option.rect.width() - - (iconsWidth + scm.border()); - const int y = option.rect.y() + scm.border(); + (propCount + 1) * scm.border(); + + QRect fitRect = QRect(0, 0, + iconsWidth, scm.rowHeight() - scm.border()); + // Move to current index + fitRect.moveTop(option.rect.topLeft().y()); + // Move to correct location. + if (option.direction == Qt::RightToLeft) { + fitRect.moveLeft(option.rect.topLeft().x()); + } else { + fitRect.moveRight(option.rect.topRight().x()); + } - return QRect(x, y, - iconsWidth, - scm.rowHeight() - scm.border()); + return fitRect; } QRect KisNodeDelegate::textRect(const QStyleOptionViewItem &option, const QModelIndex &index) const { KisNodeViewColorScheme scm; static QFont f; static int minbearing = 1337 + 666; //can be 0 or negative, 2003 is less likely if (minbearing == 2003 || f != option.font) { f = option.font; //getting your bearings can be expensive, so we cache them minbearing = option.fontMetrics.minLeftBearing() + option.fontMetrics.minRightBearing(); } - const int decorationOffset = - 2 * scm.border() + - 2 * scm.decorationMargin() + - scm.decorationSize(); + const QRect decoRect = decorationClickRect(option, index); + const QRect iconRect = iconsRect(option, index); - const int width = - iconsRect(option, index).left() - option.rect.x() - - scm.border() + minbearing - decorationOffset; + QRect rc = QRect((option.direction == Qt::RightToLeft) ? iconRect.topRight() : decoRect.topRight(), + (option.direction == Qt::RightToLeft) ? decoRect.bottomLeft() : iconRect.bottomLeft()); + rc.adjust(-(scm.border()+minbearing), 0, + (scm.border()+minbearing), 0); - return QRect(option.rect.x() - minbearing + decorationOffset, - option.rect.y() + scm.border(), - width, - scm.rowHeight() - scm.border()); + return rc; } void KisNodeDelegate::drawText(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const { KisNodeViewColorScheme scm; - const QRect rc = textRect(option, index) - .adjusted(scm.textMargin(), 0, -scm.textMargin(), 0); + const QRect rc = textRect(option, index).adjusted(scm.textMargin(), 0, + -scm.textMargin(), 0); QPen oldPen = p->pen(); const qreal oldOpacity = p->opacity(); // remember previous opacity p->setPen(option.palette.color(QPalette::Active,QPalette::Text )); - - if (!(option.state & QStyle::State_Enabled)) { p->setOpacity(0.55); } - const QString text = index.data(Qt::DisplayRole).toString(); - const QString elided = elidedText(p->fontMetrics(), rc.width(), Qt::ElideRight, text); + const QString elided = p->fontMetrics().elidedText(text, Qt::ElideRight, rc.width()); p->drawText(rc, Qt::AlignLeft | Qt::AlignVCenter, elided); p->setPen(oldPen); // restore pen settings p->setOpacity(oldOpacity); } QList KisNodeDelegate::Private::rightmostProperties(const KisBaseNode::PropertyList &props) const { QList list; QList prependList; list << OptionalProperty(0); list << OptionalProperty(0); list << OptionalProperty(0); KisBaseNode::PropertyList::const_iterator it = props.constBegin(); KisBaseNode::PropertyList::const_iterator end = props.constEnd(); for (; it != end; ++it) { if (!it->isMutable) continue; if (it->id == KisLayerPropertiesIcons::visible.id()) { // noop... } else if (it->id == KisLayerPropertiesIcons::locked.id()) { list[0] = OptionalProperty(&(*it)); } else if (it->id == KisLayerPropertiesIcons::inheritAlpha.id()) { list[1] = OptionalProperty(&(*it)); } else if (it->id == KisLayerPropertiesIcons::alphaLocked.id()) { list[2] = OptionalProperty(&(*it)); } else { prependList.prepend(OptionalProperty(&(*it))); } } { QMutableListIterator i(prependList); i.toBack(); while (i.hasPrevious()) { OptionalProperty val = i.previous(); int emptyIndex = list.lastIndexOf(0); if (emptyIndex < 0) break; list[emptyIndex] = val; i.remove(); } } return prependList + list; } int KisNodeDelegate::Private::numProperties(const QModelIndex &index) const { KisBaseNode::PropertyList props = index.data(KisNodeModel::PropertiesRole).value(); QList realProps = rightmostProperties(props); return realProps.size(); } OptionalProperty KisNodeDelegate::Private::findProperty(KisBaseNode::PropertyList &props, const OptionalProperty &refProp) const { KisBaseNode::PropertyList::iterator it = props.begin(); KisBaseNode::PropertyList::iterator end = props.end(); for (; it != end; ++it) { if (it->id == refProp->id) { return &(*it); } } return 0; } OptionalProperty KisNodeDelegate::Private::findVisibilityProperty(KisBaseNode::PropertyList &props) const { KisBaseNode::PropertyList::iterator it = props.begin(); KisBaseNode::PropertyList::iterator end = props.end(); for (; it != end; ++it) { if (it->id == KisLayerPropertiesIcons::visible.id()) { return &(*it); } } return 0; } void KisNodeDelegate::drawIcons(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const { KisNodeViewColorScheme scm; - const QRect r = iconsRect(option, index); + const QRect rc = iconsRect(option, index); QTransform oldTransform = p->transform(); QPen oldPen = p->pen(); - p->setTransform(QTransform::fromTranslate(r.x(), r.y())); + p->setTransform(QTransform::fromTranslate(rc.x(), rc.y())); p->setPen(scm.gridColor(option, d->view)); int x = 0; const int y = (scm.rowHeight() - scm.border() - scm.iconSize()) / 2; KisBaseNode::PropertyList props = index.data(KisNodeModel::PropertiesRole).value(); QList realProps = d->rightmostProperties(props); + if (option.direction == Qt::RightToLeft) { + std::reverse(realProps.begin(), realProps.end()); + } + Q_FOREACH (OptionalProperty prop, realProps) { + if (option.direction == Qt::LeftToRight) + p->drawLine(x, 0, x, scm.rowHeight() - scm.border()); + x += scm.iconMargin(); if (prop) { QIcon icon = prop->state.toBool() ? prop->onIcon : prop->offIcon; bool fullColor = prop->state.toBool() && option.state & QStyle::State_Enabled; - const qreal oldOpacity = p->opacity(); // remember previous opacity - + const qreal oldOpacity = p->opacity(); // remember previous opacity if (fullColor) { p->setOpacity(1.0); } else { p->setOpacity(0.35); } p->drawPixmap(x, y, icon.pixmap(scm.iconSize(), QIcon::Normal)); p->setOpacity(oldOpacity); // restore old opacity - - } x += scm.iconSize() + scm.iconMargin(); - p->drawLine(x, 0, x, scm.rowHeight() - scm.border()); + + if (!(option.direction == Qt::LeftToRight)) + p->drawLine(x, 0, x, scm.rowHeight() - scm.border()); x += scm.border(); } p->setTransform(oldTransform); p->setPen(oldPen); } QRect KisNodeDelegate::visibilityClickRect(const QStyleOptionViewItem &option, const QModelIndex &index) const { Q_UNUSED(index); KisNodeViewColorScheme scm; - return QRect(scm.border(), scm.border() + option.rect.top(), - 2 * scm.visibilityMargin() + scm.visibilitySize(), - scm.rowHeight() - scm.border()); + + QRect rc = scm.relVisibilityRect(); + rc.setHeight(scm.rowHeight()); + + // Move to current index + rc.moveCenter(option.rect.center()); + // Move to correct location. + if (option.direction == Qt::RightToLeft) { + // HACK: Without the -5, the right edge is outside the view + rc.moveRight(d->view->width()-5); + } else { + rc.moveLeft(0); + } + + return rc; } QRect KisNodeDelegate::decorationClickRect(const QStyleOptionViewItem &option, const QModelIndex &index) const { - Q_UNUSED(option); Q_UNUSED(index); KisNodeViewColorScheme scm; - QRect realVisualRect = d->view->originalVisualRect(index); + QRect rc = scm.relDecorationRect(); + + // Move to current index + rc.moveTop(option.rect.topLeft().y()); + rc.setHeight(scm.rowHeight()); + // Move to correct location. + if (option.direction == Qt::RightToLeft) { + rc.moveRight(option.rect.topRight().x()); + } else { + rc.moveLeft(option.rect.topLeft().x()); + } - return QRect(realVisualRect.left(), scm.border() + realVisualRect.top(), - 2 * scm.decorationMargin() + scm.decorationSize(), - scm.rowHeight() - scm.border()); + return rc; } void KisNodeDelegate::drawVisibilityIconHijack(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const { /** * Small hack Alert: * * Here wepaint over the area that sits basically outside our layer's * row. Anyway, just update it later... */ KisNodeViewColorScheme scm; KisBaseNode::PropertyList props = index.data(KisNodeModel::PropertiesRole).value(); OptionalProperty prop = d->findVisibilityProperty(props); if (!prop) return; - const int x = scm.border() + scm.visibilityMargin(); - const int y = option.rect.top() + (scm.rowHeight() - scm.border() - scm.visibilitySize()) / 2; + QRect fitRect = visibilityClickRect(option, index); + // Shrink to icon rect + fitRect = kisGrowRect(fitRect, -(scm.visibilityMargin()+scm.border())); QIcon icon = prop->state.toBool() ? prop->onIcon : prop->offIcon; // if we are not showing the layer, make the icon slightly transparent like other inactive icons const qreal oldOpacity = p->opacity(); - if (prop->state.toBool() == true) { - p->setOpacity(1.0); - } - else { + + if (!prop->state.toBool()) { p->setOpacity(0.35); } - p->drawPixmap(x, y, icon.pixmap(scm.visibilitySize(), QIcon::Normal)); + p->drawPixmap(fitRect.x(), fitRect.center().y() - scm.visibilitySize() / 2, + icon.pixmap(scm.visibilitySize(), QIcon::Normal)); p->setOpacity(oldOpacity); //// For debugging purposes only - // p->save(); - // p->setPen(Qt::blue); - // KritaUtils::renderExactRect(p, visibilityClickRect(option, index)); - // p->restore(); +// // // p->save(); +// // // p->setPen(Qt::blue); +// // // KritaUtils::renderExactRect(p, visibilityClickRect(option, index)); +// // // p->restore(); } void KisNodeDelegate::drawDecoration(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const { KisNodeViewColorScheme scm; QIcon icon = index.data(Qt::DecorationRole).value(); if (!icon.isNull()) { - QPixmap pixmap = - icon.pixmap(scm.decorationSize(), - (option.state & QStyle::State_Enabled) ? - QIcon::Normal : QIcon::Disabled); + QPixmap pixmap = icon.pixmap(scm.decorationSize(), + (option.state & QStyle::State_Enabled) ? + QIcon::Normal : QIcon::Disabled); + + QRect rc = decorationClickRect(option, index); + + // Shrink to icon rect + rc = kisGrowRect(rc, -(scm.decorationMargin()+scm.border())); - const QRect rc = scm.relDecorationRect().translated(option.rect.topLeft()); const qreal oldOpacity = p->opacity(); // remember previous opacity if (!(option.state & QStyle::State_Enabled)) { p->setOpacity(0.35); } - - p->drawPixmap(rc.topLeft(), pixmap); + p->drawPixmap(rc.topLeft()-QPoint(0, 1), pixmap); p->setOpacity(oldOpacity); // restore old opacity } } void KisNodeDelegate::drawExpandButton(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const { Q_UNUSED(index); KisNodeViewColorScheme scm; - QRect rc = scm.relExpandButtonRect().translated(option.rect.topLeft()); - rc = kisGrowRect(rc, 0); - if (!(option.state & QStyle::State_Children)) { - return; - } + QRect rc = decorationClickRect(option, index); + + // Move to current index +// rc.moveTop(option.rect.topLeft().y()); + // Shrink to icon rect + rc = kisGrowRect(rc, -(scm.decorationMargin()+scm.border())); + + if (!(option.state & QStyle::State_Children)) return; + - QString iconName = option.state & QStyle::State_Open ? "arrow-down" : "arrow-right"; + QString iconName = option.state & QStyle::State_Open ? + "arrow-down" : ((option.direction == Qt::RightToLeft) ? "arrow-left" : "arrow-right"); QIcon icon = KisIconUtils::loadIcon(iconName); QPixmap pixmap = icon.pixmap(rc.width(), (option.state & QStyle::State_Enabled) ? QIcon::Normal : QIcon::Disabled); - p->drawPixmap(rc.topLeft(), pixmap); + p->drawPixmap(rc.bottomLeft()-QPoint(0, scm.decorationSize()-1), pixmap); } void KisNodeDelegate::Private::toggleProperty(KisBaseNode::PropertyList &props, OptionalProperty clickedProperty, bool controlPressed, const QModelIndex &index) { QAbstractItemModel *model = view->model(); // Using Ctrl+click to enter stasis if (controlPressed && clickedProperty->canHaveStasis) { // STEP 0: Prepare to Enter or Leave control key stasis quint16 numberOfLeaves = model->rowCount(index.parent()); QModelIndex eachItem; // STEP 1: Go. if (clickedProperty->isInStasis == false) { // Enter /* Make every leaf of this node go State = False, saving the old property value to stateInStasis */ for (quint16 i = 0; i < numberOfLeaves; ++i) { // Foreach leaf in the node (index.parent()) eachItem = model->index(i, 1, index.parent()); // The entire property list has to be altered because model->setData cannot set individual properties KisBaseNode::PropertyList eachPropertyList = eachItem.data(KisNodeModel::PropertiesRole).value(); OptionalProperty prop = findProperty(eachPropertyList, clickedProperty); if (!prop) continue; prop->stateInStasis = prop->state.toBool(); prop->state = eachItem == index; prop->isInStasis = true; model->setData(eachItem, QVariant::fromValue(eachPropertyList), KisNodeModel::PropertiesRole); } for (quint16 i = 0; i < numberOfLeaves; ++i) { // Foreach leaf in the node (index.parent()) eachItem = model->index(i, 1, index.parent()); KisBaseNode::PropertyList eachPropertyList = eachItem.data(KisNodeModel::PropertiesRole).value(); OptionalProperty prop = findProperty(eachPropertyList, clickedProperty); if (!prop) continue; } } else { // Leave /* Make every leaf of this node go State = stateInStasis */ for (quint16 i = 0; i < numberOfLeaves; ++i) { eachItem = model->index(i, 1, index.parent()); // The entire property list has to be altered because model->setData cannot set individual properties KisBaseNode::PropertyList eachPropertyList = eachItem.data(KisNodeModel::PropertiesRole).value(); OptionalProperty prop = findProperty(eachPropertyList, clickedProperty); if (!prop) continue; prop->state = prop->stateInStasis; prop->isInStasis = false; model->setData(eachItem, QVariant::fromValue(eachPropertyList), KisNodeModel::PropertiesRole); } } } else { clickedProperty->state = !clickedProperty->state.toBool(); model->setData(index, QVariant::fromValue(props), KisNodeModel::PropertiesRole); } } bool KisNodeDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { KisNodeViewColorScheme scm; + QStyleOptionViewItem newOption = option; + newOption.rect = d->view->originalVisualRect(index); + if ((event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonDblClick) && (index.flags() & Qt::ItemIsEnabled)) { QMouseEvent *mouseEvent = static_cast(event); /** * Small hack Alert: * * Here we handle clicking even when it happened outside * the rectangle of the current index. The point is, we * use some virtual scroling offset to move the tree to the * right of the visibility icon. So the icon itself is placed * in an empty area that doesn't belong to any index. But we still * handle it. */ - const QRect iconsRect = this->iconsRect(option, index); - const bool iconsClicked = iconsRect.isValid() && - iconsRect.contains(mouseEvent->pos()); - - const QRect visibilityRect = visibilityClickRect(option, index); + const QRect visibilityRect = visibilityClickRect(newOption, index); const bool visibilityClicked = visibilityRect.isValid() && visibilityRect.contains(mouseEvent->pos()); - const QRect decorationRect = decorationClickRect(option, index); + const QRect thumbnailRect = thumbnailClickRect(newOption, index); + const bool thumbnailClicked = thumbnailRect.isValid() && + thumbnailRect.contains(mouseEvent->pos()); + + const QRect decorationRect = decorationClickRect(newOption, index); const bool decorationClicked = decorationRect.isValid() && decorationRect.contains(mouseEvent->pos()); - const bool leftButton = mouseEvent->buttons() & Qt::LeftButton; + const QRect iconsRect = this->iconsRect(newOption, index); + const bool iconsClicked = iconsRect.isValid() && + iconsRect.contains(mouseEvent->pos()); - const QRect thumbnailRect = thumbnailClickRect(option, index); - const bool thumbnailClicked = thumbnailRect.contains(mouseEvent->pos()); + const bool leftButton = mouseEvent->buttons() & Qt::LeftButton; if (leftButton && iconsClicked) { KisBaseNode::PropertyList props = index.data(KisNodeModel::PropertiesRole).value(); QList realProps = d->rightmostProperties(props); + if (newOption.direction == Qt::RightToLeft) { + std::reverse(realProps.begin(), realProps.end()); + } const int numProps = realProps.size(); const int iconWidth = scm.iconSize() + 2 * scm.iconMargin() + scm.border(); const int xPos = mouseEvent->pos().x() - iconsRect.left(); const int clickedIcon = xPos / iconWidth; const int distToBorder = qMin(xPos % iconWidth, iconWidth - xPos % iconWidth); if (iconsClicked && clickedIcon >= 0 && clickedIcon < numProps && distToBorder > scm.iconMargin()) { OptionalProperty clickedProperty = realProps[clickedIcon]; if (!clickedProperty) return false; d->toggleProperty(props, clickedProperty, mouseEvent->modifiers() == Qt::ControlModifier, index); return true; } } else if (leftButton && visibilityClicked) { KisBaseNode::PropertyList props = index.data(KisNodeModel::PropertiesRole).value(); OptionalProperty clickedProperty = d->findVisibilityProperty(props); if (!clickedProperty) return false; d->toggleProperty(props, clickedProperty, mouseEvent->modifiers() == Qt::ControlModifier, index); return true; } else if (leftButton && decorationClicked) { bool isExpandable = model->hasChildren(index); if (isExpandable) { bool isExpanded = d->view->isExpanded(index); d->view->setExpanded(index, !isExpanded); } return true; } else if (leftButton && thumbnailClicked) { bool hasCorrectModifier = false; SelectionAction action = SELECTION_REPLACE; if (mouseEvent->modifiers() == Qt::ControlModifier) { action = SELECTION_REPLACE; hasCorrectModifier = true; } else if (mouseEvent->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { action = SELECTION_ADD; hasCorrectModifier = true; } else if (mouseEvent->modifiers() == (Qt::ControlModifier | Qt::AltModifier)) { action = SELECTION_SUBTRACT; hasCorrectModifier = true; } else if (mouseEvent->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier | Qt::AltModifier)) { action = SELECTION_INTERSECT; hasCorrectModifier = true; } if (hasCorrectModifier) { model->setData(index, QVariant(int(action)), KisNodeModel::SelectOpaqueRole); - return true; } + return true; //If not here then the item is !expanded when reaching return false; } if (mouseEvent->button() == Qt::LeftButton && mouseEvent->modifiers() == Qt::AltModifier) { d->view->setCurrentIndex(index); model->setData(index, true, KisNodeModel::AlternateActiveRole); return true; } } else if (event->type() == QEvent::ToolTip) { if (!KisConfig(true).hidePopups()) { QHelpEvent *helpEvent = static_cast(event); - d->tip.showTip(d->view, helpEvent->pos(), option, index); + d->tip.showTip(d->view, helpEvent->pos(), newOption, index); } return true; } else if (event->type() == QEvent::Leave) { d->tip.hide(); } return false; } QWidget *KisNodeDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem&, const QModelIndex&) const { d->edit = new QLineEdit(parent); d->edit->setFocusPolicy(Qt::StrongFocus); d->edit->installEventFilter(const_cast(this)); //hack? return d->edit; } void KisNodeDelegate::setEditorData(QWidget *widget, const QModelIndex &index) const { QLineEdit *edit = qobject_cast(widget); Q_ASSERT(edit); edit->setText(index.data(Qt::DisplayRole).toString()); } void KisNodeDelegate::setModelData(QWidget *widget, QAbstractItemModel *model, const QModelIndex &index) const { QLineEdit *edit = qobject_cast(widget); Q_ASSERT(edit); model->setData(index, edit->text(), Qt::DisplayRole); } void KisNodeDelegate::updateEditorGeometry(QWidget *widget, const QStyleOptionViewItem &option, const QModelIndex &index) const { Q_UNUSED(index); widget->setGeometry(option.rect); } // PROTECTED bool KisNodeDelegate::eventFilter(QObject *object, QEvent *event) { switch (event->type()) { case QEvent::MouseButtonPress: { if (d->edit) { QMouseEvent *me = static_cast(event); if (!QRect(d->edit->mapToGlobal(QPoint()), d->edit->size()).contains(me->globalPos())) { emit commitData(d->edit); emit closeEditor(d->edit); } } } break; case QEvent::KeyPress: { QLineEdit *edit = qobject_cast(object); if (edit && edit == d->edit) { QKeyEvent *ke = static_cast(event); switch (ke->key()) { case Qt::Key_Escape: emit closeEditor(edit); return true; case Qt::Key_Tab: emit commitData(edit); emit closeEditor(edit, EditNextItem); return true; case Qt::Key_Backtab: emit commitData(edit); emit closeEditor(edit, EditPreviousItem); return true; case Qt::Key_Return: case Qt::Key_Enter: emit commitData(edit); emit closeEditor(edit); return true; default: break; } } } break; case QEvent::ShortcutOverride : { QLineEdit *edit = qobject_cast(object); if (edit && edit == d->edit){ auto* key = static_cast(event); if (key->modifiers() == Qt::NoModifier){ switch (key->key()){ case Qt::Key_Escape: case Qt::Key_Tab: case Qt::Key_Backtab: case Qt::Key_Return: case Qt::Key_Enter: event->accept(); return true; default: break; } } } } break; case QEvent::FocusOut : { QLineEdit *edit = qobject_cast(object); if (edit && edit == d->edit) { emit commitData(edit); emit closeEditor(edit); } } default: break; } return QAbstractItemDelegate::eventFilter(object, event); } // PRIVATE QStyleOptionViewItem KisNodeDelegate::getOptions(const QStyleOptionViewItem &o, const QModelIndex &index) { QStyleOptionViewItem option = o; QVariant v = index.data(Qt::FontRole); if (v.isValid()) { option.font = v.value(); option.fontMetrics = QFontMetrics(option.font); } v = index.data(Qt::TextAlignmentRole); if (v.isValid()) option.displayAlignment = QFlag(v.toInt()); v = index.data(Qt::TextColorRole); if (v.isValid()) option.palette.setColor(QPalette::Text, v.value()); v = index.data(Qt::BackgroundColorRole); if (v.isValid()) option.palette.setColor(QPalette::Window, v.value()); return option; } void KisNodeDelegate::drawProgressBar(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const { QVariant value = index.data(KisNodeModel::ProgressRole); if (!value.isNull() && (value.toInt() >= 0 && value.toInt() <= 100)) { /// The progress bar will display under the layer name area. The bars have accurate data, so we /// probably don't need to also show the actual number for % complete KisNodeViewColorScheme scm; - const int width = textRect(option, index).width() + scm.iconSize()*2; + + const QRect thumbnailRect = thumbnailClickRect(option, index); + const QRect iconsRectR = iconsRect(option, index); const int height = 5; - const QPoint base = option.rect.bottomLeft() - QPoint(0, height ); - const QRect r = QRect(base.x(), base.y(), width, height); + const QRect rc = QRect( + ((option.direction == Qt::RightToLeft) ? iconsRectR.bottomRight() + : thumbnailRect.bottomRight()) - QPoint(0, height), + ((option.direction == Qt::RightToLeft) ? thumbnailRect.bottomLeft() + : iconsRectR.bottomLeft())); p->save(); { - p->setClipRect(r); + p->setClipRect(rc); QStyle* style = QApplication::style(); QStyleOptionProgressBar opt; opt.minimum = 0; opt.maximum = 100; opt.progress = value.toInt(); opt.textVisible = false; opt.textAlignment = Qt::AlignHCenter; opt.text = i18n("%1 %", opt.progress); - opt.rect = r; opt.orientation = Qt::Horizontal; opt.state = option.state; style->drawControl(QStyle::CE_ProgressBar, &opt, p, 0); } p->restore(); } } void KisNodeDelegate::slotConfigChanged() { KisConfig cfg(true); d->checkersColor1 = cfg.checkersColor1(); d->checkersColor2 = cfg.checkersColor2(); } void KisNodeDelegate::slotUpdateIcon() { KisLayerPropertiesIcons::instance()->updateIcons(); } diff --git a/libs/ui/KisNodeDelegate.h b/libs/ui/KisNodeDelegate.h index ad53f443e1..048eee631e 100644 --- a/libs/ui/KisNodeDelegate.h +++ b/libs/ui/KisNodeDelegate.h @@ -1,85 +1,89 @@ /* Copyright (c) 2006 Gábor Lehel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_DOCUMENT_SECTION_DELEGATE_H #define KIS_DOCUMENT_SECTION_DELEGATE_H #include class KisNodeView; class KisNodeModel; /** * See KisNodeModel and KisNodeView. * * A delegate provides the gui machinery, using Qt's model/view terminology. * This class is owned by KisNodeView to do the work of generating the * graphical representation of each item. */ class KisNodeDelegate: public QAbstractItemDelegate { Q_OBJECT public: explicit KisNodeDelegate(KisNodeView *view, QObject *parent = 0); ~KisNodeDelegate() override; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override; QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; void setEditorData(QWidget *editor, const QModelIndex &index) const override; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override; void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex& index) const override; void slotUpdateIcon(); protected: bool eventFilter(QObject *object, QEvent *event) override; private: typedef KisNodeModel Model; typedef KisNodeView View; class Private; Private* const d; static QStyleOptionViewItem getOptions(const QStyleOptionViewItem &option, const QModelIndex &index); void drawProgressBar(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const; void drawBranch(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const; void drawColorLabel(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const; void drawFrame(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const; + + QRect thumbnailClickRect(const QStyleOptionViewItem &option, const QModelIndex &index) const; void drawThumbnail(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const; + QRect iconsRect(const QStyleOptionViewItem &option, const QModelIndex &index) const; QRect textRect(const QStyleOptionViewItem &option, const QModelIndex &index) const; void drawText(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const; void drawIcons(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const; + QRect visibilityClickRect(const QStyleOptionViewItem &option, const QModelIndex &index) const; - QRect decorationClickRect(const QStyleOptionViewItem &option, const QModelIndex &index) const; - QRect thumbnailClickRect(const QStyleOptionViewItem &option, const QModelIndex &index) const; void drawVisibilityIconHijack(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const; + + QRect decorationClickRect(const QStyleOptionViewItem &option, const QModelIndex &index) const; void drawDecoration(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const; void drawExpandButton(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const; private Q_SLOTS: void slotConfigChanged(); }; #endif diff --git a/libs/ui/KisNodeView.cpp b/libs/ui/KisNodeView.cpp index af0dcb65d6..26a1ad4aaa 100644 --- a/libs/ui/KisNodeView.cpp +++ b/libs/ui/KisNodeView.cpp @@ -1,586 +1,592 @@ /* Copyright (c) 2006 Gábor Lehel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KisNodeView.h" #include "KisNodePropertyAction_p.h" #include "KisNodeDelegate.h" #include "kis_node_view_visibility_delegate.h" #include "kis_node_model.h" #include "kis_signals_blocker.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_node_view_color_scheme.h" #ifdef HAVE_X11 #define DRAG_WHILE_DRAG_WORKAROUND #endif #ifdef DRAG_WHILE_DRAG_WORKAROUND #define DRAG_WHILE_DRAG_WORKAROUND_START() d->isDragging = true #define DRAG_WHILE_DRAG_WORKAROUND_STOP() d->isDragging = false #else #define DRAG_WHILE_DRAG_WORKAROUND_START() #define DRAG_WHILE_DRAG_WORKAROUND_STOP() #endif class Q_DECL_HIDDEN KisNodeView::Private { public: Private(KisNodeView* _q) : delegate(_q, _q) , mode(DetailedMode) #ifdef DRAG_WHILE_DRAG_WORKAROUND , isDragging(false) #endif { KSharedConfigPtr config = KSharedConfig::openConfig(); KConfigGroup group = config->group("NodeView"); mode = (DisplayMode) group.readEntry("NodeViewMode", (int)MinimalMode); } KisNodeDelegate delegate; DisplayMode mode; QPersistentModelIndex hovered; QPoint lastPos; #ifdef DRAG_WHILE_DRAG_WORKAROUND bool isDragging; #endif }; KisNodeView::KisNodeView(QWidget *parent) : QTreeView(parent) , m_draggingFlag(false) , d(new Private(this)) { setItemDelegateForColumn(0, &d->delegate); setMouseTracking(true); setSelectionBehavior(SelectRows); setDefaultDropAction(Qt::MoveAction); setVerticalScrollMode(QAbstractItemView::ScrollPerItem); setSelectionMode(QAbstractItemView::ExtendedSelection); header()->hide(); setDragEnabled(true); setDragDropMode(QAbstractItemView::DragDrop); setAcceptDrops(true); setDropIndicatorShown(true); { QScroller *scroller = KisKineticScroller::createPreconfiguredScroller(this); if (scroller) { connect(scroller, SIGNAL(stateChanged(QScroller::State)), this, SLOT(slotScrollerStateChanged(QScroller::State))); } } } KisNodeView::~KisNodeView() { delete d; } void KisNodeView::setDisplayMode(DisplayMode mode) { if (d->mode != mode) { d->mode = mode; KSharedConfigPtr config = KSharedConfig::openConfig(); KConfigGroup group = config->group("NodeView"); group.writeEntry("NodeViewMode", (int)mode); scheduleDelayedItemsLayout(); } } KisNodeView::DisplayMode KisNodeView::displayMode() const { return d->mode; } void KisNodeView::addPropertyActions(QMenu *menu, const QModelIndex &index) { KisBaseNode::PropertyList list = index.data(KisNodeModel::PropertiesRole).value(); for (int i = 0, n = list.count(); i < n; ++i) { if (list.at(i).isMutable) { PropertyAction *a = new PropertyAction(i, list.at(i), index, menu); connect(a, SIGNAL(toggled(bool,QPersistentModelIndex,int)), this, SLOT(slotActionToggled(bool,QPersistentModelIndex,int))); menu->addAction(a); } } } void KisNodeView::updateNode(const QModelIndex &index) { dataChanged(index, index); } QItemSelectionModel::SelectionFlags KisNodeView::selectionCommand(const QModelIndex &index, const QEvent *event) const { /** * Qt has a bug: when we Ctrl+click on an item, the item's * selections gets toggled on mouse *press*, whereas usually it is * done on mouse *release*. Therefore the user cannot do a * Ctrl+D&D with the default configuration. This code fixes the * problem by manually returning QItemSelectionModel::NoUpdate * flag when the user clicks on an item and returning * QItemSelectionModel::Toggle on release. */ if (event && (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease) && index.isValid()) { const QMouseEvent *mevent = static_cast(event); if (mevent->button() == Qt::RightButton && selectionModel()->selectedIndexes().contains(index)) { // Allow calling context menu for multiple layers return QItemSelectionModel::NoUpdate; } if (event->type() == QEvent::MouseButtonPress && (mevent->modifiers() & Qt::ControlModifier)) { return QItemSelectionModel::NoUpdate; } if (event->type() == QEvent::MouseButtonRelease && (mevent->modifiers() & Qt::ControlModifier)) { return QItemSelectionModel::Toggle; } } /** * Qt 5.6 has a bug: it reads global modifiers, not the ones * passed from event. So if you paste an item using Ctrl+V it'll * select multiple layers for you */ Qt::KeyboardModifiers globalModifiers = QApplication::keyboardModifiers(); if (!event && globalModifiers != Qt::NoModifier) { return QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows; } return QAbstractItemView::selectionCommand(index, event); } + QRect KisNodeView::visualRect(const QModelIndex &index) const { QRect rc = QTreeView::visualRect(index); - rc.setLeft(0); + if (layoutDirection() == Qt::RightToLeft) + rc.setRight(width()); + else + rc.setLeft(0); return rc; } QRect KisNodeView::originalVisualRect(const QModelIndex &index) const { return QTreeView::visualRect(index); } QModelIndex KisNodeView::indexAt(const QPoint &point) const { KisNodeViewColorScheme scm; QModelIndex index = QTreeView::indexAt(point); - if (!index.isValid() && point.x() < scm.visibilityColumnWidth()) { - index = QTreeView::indexAt(point + QPoint(scm.visibilityColumnWidth(), 0)); + if (!index.isValid()) { + // Middle is a good position for both LTR and RTL layouts + // First reset x, then get the x in the middle + index = QTreeView::indexAt(point - QPoint(point.x(), 0) + QPoint(width() / 2, 0)); } return index; } bool KisNodeView::viewportEvent(QEvent *e) { if (model()) { switch(e->type()) { case QEvent::MouseButtonPress: { DRAG_WHILE_DRAG_WORKAROUND_STOP(); const QPoint pos = static_cast(e)->pos(); d->lastPos = pos; if (!indexAt(pos).isValid()) { return QTreeView::viewportEvent(e); } QModelIndex index = model()->buddy(indexAt(pos)); if (d->delegate.editorEvent(e, model(), optionForIndex(index), index)) { return true; } } break; case QEvent::Leave: { QEvent e(QEvent::Leave); d->delegate.editorEvent(&e, model(), optionForIndex(d->hovered), d->hovered); d->hovered = QModelIndex(); } break; case QEvent::MouseMove: { #ifdef DRAG_WHILE_DRAG_WORKAROUND if (d->isDragging) { return false; } #endif const QPoint pos = static_cast(e)->pos(); QModelIndex hovered = indexAt(pos); if (hovered != d->hovered) { if (d->hovered.isValid()) { QEvent e(QEvent::Leave); d->delegate.editorEvent(&e, model(), optionForIndex(d->hovered), d->hovered); } if (hovered.isValid()) { QEvent e(QEvent::Enter); d->delegate.editorEvent(&e, model(), optionForIndex(hovered), hovered); } d->hovered = hovered; } /* This is a workaround for a bug in QTreeView that immediately begins a dragging action when the mouse lands on the decoration/icon of a different index and moves 1 pixel or more */ Qt::MouseButtons buttons = static_cast(e)->buttons(); if ((Qt::LeftButton | Qt::MidButton) & buttons) { if ((pos - d->lastPos).manhattanLength() > qApp->startDragDistance()) { return QTreeView::viewportEvent(e); } return true; } } break; case QEvent::ToolTip: { const QPoint pos = static_cast(e)->pos(); if (!indexAt(pos).isValid()) { return QTreeView::viewportEvent(e); } QModelIndex index = model()->buddy(indexAt(pos)); return d->delegate.editorEvent(e, model(), optionForIndex(index), index); } break; case QEvent::Resize: { scheduleDelayedItemsLayout(); break; } default: break; } } return QTreeView::viewportEvent(e); } void KisNodeView::contextMenuEvent(QContextMenuEvent *e) { QTreeView::contextMenuEvent(e); QModelIndex i = indexAt(e->pos()); if (model()) i = model()->buddy(i); showContextMenu(e->globalPos(), i); } void KisNodeView::showContextMenu(const QPoint &globalPos, const QModelIndex &index) { emit contextMenuRequested(globalPos, index); } void KisNodeView::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) { QTreeView::currentChanged(current, previous); if (current != previous) { Q_ASSERT(!current.isValid() || current.model() == model()); model()->setData(current, true, KisNodeModel::ActiveRole); } } void KisNodeView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &/*roles*/) { QTreeView::dataChanged(topLeft, bottomRight); for (int x = topLeft.row(); x <= bottomRight.row(); ++x) { for (int y = topLeft.column(); y <= bottomRight.column(); ++y) { QModelIndex index = topLeft.sibling(x, y); if (index.data(KisNodeModel::ActiveRole).toBool()) { if (currentIndex() != index) { setCurrentIndex(index); } return; } } } } void KisNodeView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) { QTreeView::selectionChanged(selected, deselected); emit selectionChanged(selectedIndexes()); } void KisNodeView::slotActionToggled(bool on, const QPersistentModelIndex &index, int num) { KisBaseNode::PropertyList list = index.data(KisNodeModel::PropertiesRole).value(); list[num].state = on; const_cast(index.model())->setData(index, QVariant::fromValue(list), KisNodeModel::PropertiesRole); } QStyleOptionViewItem KisNodeView::optionForIndex(const QModelIndex &index) const { QStyleOptionViewItem option = viewOptions(); option.rect = visualRect(index); if (index == currentIndex()) option.state |= QStyle::State_HasFocus; return option; } void KisNodeView::startDrag(Qt::DropActions supportedActions) { DRAG_WHILE_DRAG_WORKAROUND_START(); if (displayMode() == KisNodeView::ThumbnailMode) { const QModelIndexList indexes = selectionModel()->selectedIndexes(); if (!indexes.isEmpty()) { QMimeData *data = model()->mimeData(indexes); if (!data) { return; } QDrag *drag = new QDrag(this); drag->setPixmap(createDragPixmap()); drag->setMimeData(data); //m_dragSource = this; drag->exec(supportedActions); } } else { QTreeView::startDrag(supportedActions); } } QPixmap KisNodeView::createDragPixmap() const { const QModelIndexList selectedIndexes = selectionModel()->selectedIndexes(); Q_ASSERT(!selectedIndexes.isEmpty()); const int itemCount = selectedIndexes.count(); // If more than one item is dragged, align the items inside a // rectangular grid. The maximum grid size is limited to 4 x 4 items. int xCount = 2; int size = 96; if (itemCount > 9) { xCount = 4; size = KisIconUtils::SizeLarge; } else if (itemCount > 4) { xCount = 3; size = KisIconUtils::SizeHuge; } else if (itemCount < xCount) { xCount = itemCount; } int yCount = itemCount / xCount; if (itemCount % xCount != 0) { ++yCount; } if (yCount > xCount) { yCount = xCount; } // Draw the selected items into the grid cells QPixmap dragPixmap(xCount * size + xCount - 1, yCount * size + yCount - 1); dragPixmap.fill(Qt::transparent); QPainter painter(&dragPixmap); int x = 0; int y = 0; Q_FOREACH (const QModelIndex &selectedIndex, selectedIndexes) { const QImage img = selectedIndex.data(int(KisNodeModel::BeginThumbnailRole) + size).value(); painter.drawPixmap(x, y, QPixmap().fromImage(img.scaled(QSize(size, size), Qt::KeepAspectRatio, Qt::SmoothTransformation))); x += size + 1; if (x >= dragPixmap.width()) { x = 0; y += size + 1; } if (y >= dragPixmap.height()) { break; } } return dragPixmap; } void KisNodeView::resizeEvent(QResizeEvent * event) { KisNodeViewColorScheme scm; header()->setStretchLastSection(false); header()->setOffset(-scm.visibilityColumnWidth()); header()->resizeSection(0, event->size().width() - scm.visibilityColumnWidth()); setIndentation(scm.indentation()); QTreeView::resizeEvent(event); } void KisNodeView::paintEvent(QPaintEvent *event) { event->accept(); QTreeView::paintEvent(event); // Paint the line where the slide should go if (isDragging() && (displayMode() == KisNodeView::ThumbnailMode)) { QSize size(visualRect(model()->index(0, 0, QModelIndex())).width(), visualRect(model()->index(0, 0, QModelIndex())).height()); int numberRow = cursorPageIndex(); int scrollBarValue = verticalScrollBar()->value(); QPoint point1(0, numberRow * size.height() - scrollBarValue); QPoint point2(size.width(), numberRow * size.height() - scrollBarValue); QLineF line(point1, point2); QPainter painter(this->viewport()); QPen pen = QPen(palette().brush(QPalette::Highlight), 8); pen.setCapStyle(Qt::RoundCap); painter.setPen(pen); painter.setOpacity(0.8); painter.drawLine(line); } } void KisNodeView::drawBranches(QPainter *painter, const QRect &rect, const QModelIndex &index) const { Q_UNUSED(painter); Q_UNUSED(rect); Q_UNUSED(index); /** * Noop... Everything is going to be painted by KisNodeDelegate. * So this override basically disables painting of Qt's branch-lines. */ } void KisNodeView::dropEvent(QDropEvent *ev) { if (displayMode() == KisNodeView::ThumbnailMode) { setDraggingFlag(false); ev->accept(); clearSelection(); if (!model()) { return; } int newIndex = cursorPageIndex(); model()->dropMimeData(ev->mimeData(), ev->dropAction(), newIndex, -1, QModelIndex()); return; } QTreeView::dropEvent(ev); DRAG_WHILE_DRAG_WORKAROUND_STOP(); } int KisNodeView::cursorPageIndex() const { QSize size(visualRect(model()->index(0, 0, QModelIndex())).width(), visualRect(model()->index(0, 0, QModelIndex())).height()); int scrollBarValue = verticalScrollBar()->value(); QPoint cursorPosition = QWidget::mapFromGlobal(QCursor::pos()); int numberRow = (cursorPosition.y() + scrollBarValue) / size.height(); //If cursor is at the half button of the page then the move action is performed after the slide, otherwise it is //performed before the page if (abs((cursorPosition.y() + scrollBarValue) - size.height()*numberRow) > (size.height()/2)) { numberRow++; } if (numberRow > model()->rowCount(QModelIndex())) { numberRow = model()->rowCount(QModelIndex()); } return numberRow; } void KisNodeView::dragEnterEvent(QDragEnterEvent *ev) { DRAG_WHILE_DRAG_WORKAROUND_START(); QVariant data = qVariantFromValue( static_cast(const_cast(ev->mimeData()))); model()->setData(QModelIndex(), data, KisNodeModel::DropEnabled); QTreeView::dragEnterEvent(ev); } void KisNodeView::dragMoveEvent(QDragMoveEvent *ev) { DRAG_WHILE_DRAG_WORKAROUND_START(); if (displayMode() == KisNodeView::ThumbnailMode) { ev->accept(); if (!model()) { return; } QTreeView::dragMoveEvent(ev); setDraggingFlag(); viewport()->update(); return; } QTreeView::dragMoveEvent(ev); } void KisNodeView::dragLeaveEvent(QDragLeaveEvent *e) { if (displayMode() == KisNodeView::ThumbnailMode) { setDraggingFlag(false); } else { QTreeView::dragLeaveEvent(e); } DRAG_WHILE_DRAG_WORKAROUND_STOP(); } bool KisNodeView::isDragging() const { return m_draggingFlag; } void KisNodeView::setDraggingFlag(bool flag) { m_draggingFlag = flag; } void KisNodeView::slotUpdateIcons() { d->delegate.slotUpdateIcon(); } void KisNodeView::slotScrollerStateChanged(QScroller::State state){ KisKineticScroller::updateCursor(this, state); } diff --git a/libs/ui/KisOpenPane.h b/libs/ui/KisOpenPane.h index 79c8d82aba..34e7bbd3b6 100644 --- a/libs/ui/KisOpenPane.h +++ b/libs/ui/KisOpenPane.h @@ -1,108 +1,109 @@ /* This file is part of the KDE project Copyright (C) 2005 Peter Simonsson This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KISOPENPANE_H #define KISOPENPANE_H #include #include #include #include class KisDetailsPane; class KisDocument; class KisOpenPanePrivate; class KisTemplatesPane; class QPixmap; class QString; class QStringList; class QTreeWidgetItem; class QUrl; /// \internal class KisOpenPane : public QDialog { Q_OBJECT public: /** * Constructor - * @param parent the parent widget - * @param templateType the template-type (group) that should be selected on creation. + * @param parent the parent widget. + * @param mimeFilter the template-type (group) that should be selected on creation. + * @param templatesResourcePath the path to the templates. */ KisOpenPane(QWidget *parent, const QStringList& mimeFilter, const QString& templatesResourcePath = QString()); ~KisOpenPane() override; QTreeWidgetItem* addPane(const QString &title, const QString &iconName, QWidget *widget, int sortWeight); QTreeWidgetItem* addPane(const QString& title, const QPixmap& icon, QWidget* widget, int sortWeight); /** * If the application has a way to create a document not based on a template, but on user * provided settings, the widget showing these gets set here. * @see KisDocument::createCustomDocumentWidget() * @param widget the widget. * @param title the title shown in the sidebar * @param icon the icon shown in the sidebar */ void addCustomDocumentWidget(QWidget *widget, const QString& title = QString(), const QString& icon = QString()); Q_SIGNALS: /// this signal is emitted (as defined by KisDocument) the moment the document is 'ready' void documentSelected(KisDocument*); protected Q_SLOTS: void updateSelectedWidget(); void itemClicked(QTreeWidgetItem* item); /// Saves the splitter sizes for KisDetailsPaneBase based panes void saveSplitterSizes(KisDetailsPane* sender, const QList& sizes); private Q_SLOTS: /// when clicked "Open Existing Document" button void openFileDialog(); Q_SIGNALS: void openExistingFile(const QUrl&); void openTemplate(const QUrl&); /// Emitted when the always use template has changed void alwaysUseChanged(KisTemplatesPane* sender, const QString& alwaysUse); /// Emitted when one of the detail panes have changed it's splitter void splitterResized(KisDetailsPane* sender, const QList& sizes); void cancelButton(); protected: /** * Populate the list with all templates the user can choose. * @param templatesResourcePath the template-type (group) that should be selected on creation. */ void initTemplates(const QString& templatesResourcePath); // QWidget overrides void dragEnterEvent(QDragEnterEvent * event) override; void dropEvent(QDropEvent * event) override; private: QStringList m_mimeFilter; KisOpenPanePrivate * const d; }; #endif //KOOPENPANE_H diff --git a/libs/ui/KisPaletteEditor.h b/libs/ui/KisPaletteEditor.h index 7596294f89..2efae6a7c8 100644 --- a/libs/ui/KisPaletteEditor.h +++ b/libs/ui/KisPaletteEditor.h @@ -1,148 +1,146 @@ /* * Copyright (c) 2018 Michael Zhou * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KISPALETTEMANAGER_H #define KISPALETTEMANAGER_H #include #include #include #include class KoColorSet; class KisPaletteModel; class KisViewManager; class KisSwatchGroup; class KisViewManager; /** * @brief The PaletteEditor class * this class manipulates a KisPaletteModel using GUI elements and communicate * with KisDocument * * Changes made in this class won't be done to the palette if the palette is * read only (not editable, isEditable() == false) */ class KRITAUI_EXPORT KisPaletteEditor : public QObject { Q_OBJECT public: struct PaletteInfo; public: explicit KisPaletteEditor(QObject *parent = Q_NULLPTR); ~KisPaletteEditor(); void setPaletteModel(KisPaletteModel *model); void setView(KisViewManager *view); void addPalette(); void importPalette(); void removePalette(KoColorSetSP ); /** * @brief rowNumberOfGroup * @param oriName the original name of a group at the creation of the instance * @return newest row number of the group */ int rowNumberOfGroup(const QString &oriName) const; /** * @brief oldNameFromNewName * @param newName the current name of a group * @return the name of the group at the creation of the instance */ QString oldNameFromNewName(const QString &newName) const; /** * @brief duplicateExistsFilename - * @param name + * @param filename the name of the file * @param global if this filename is going to be used for a global palette * @return true if the a palette in the resource system that has filename * name already exists else false */ bool duplicateExistsFilename(const QString &filename, bool global) const; QString relativePathFromSaveLocation() const; void rename(const QString &newName); void changeFilename(const QString &newName); void changeColCount(int); /** * @brief addGroup - * @param name original group name - * @param rowNumber - * @return new group's name if change accpeted, empty string if cancelled + * @return new group's name if change accepted, empty string if cancelled */ QString addGroup(); /** * @brief removeGroup * @param name original group name * @return true if change accepted, false if cancelled */ bool removeGroup(const QString &name); /** * @brief renameGroup * @param oldName * @return new name if change accpeted, empty string if cancelled */ QString renameGroup(const QString &oldName); void changeGroupRowCount(const QString &name, int newRowCount); void setGlobal(bool); void setReadOnly(bool); void setEntry(const KoColor &color, const QModelIndex &index); void removeEntry(const QModelIndex &index); void modifyEntry(const QModelIndex &index); void addEntry(const KoColor &color); bool isModified() const; /** * @brief getModifiedGroup * @param originalName name of the group at the creation of the instance * @return the modified group */ const KisSwatchGroup &getModifiedGroup(const QString &originalName) const; /** * @brief updatePalette * MUST be called to make the changes into the resource server */ void updatePalette(); private Q_SLOTS: void slotGroupNameChanged(const QString &newName); void slotPaletteChanged(); void slotSetDocumentModified(); private: QString newPaletteFileName(bool isGlobal); QString newGroupName() const; void setNonGlobal(); void setGlobal(); bool duplicateExistsGroupName(const QString &name) const; bool duplicateExistsOriginalGroupName(const QString &name) const; void uploadPaletteList() const; QString filenameFromPath(const QString &path) const; private: struct Private; QScopedPointer m_d; }; #endif // KISPALETTEMANAGER_H diff --git a/libs/ui/KisPrintJob.h b/libs/ui/KisPrintJob.h index d0ab757f04..0698448f15 100644 --- a/libs/ui/KisPrintJob.h +++ b/libs/ui/KisPrintJob.h @@ -1,95 +1,95 @@ /* This file is part of the KDE project * Copyright (C) 2007 Thomas Zander * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KISPRINTJOB_H #define KISPRINTJOB_H #include #include #include #include #include "kritaui_export.h" #include /** * A print job is an interface that the KisView uses to create an application-specific * class that can take care of printing. * The printjob should be able to print again after a print job has been completed, * using the same QPrinter to allow the user to alter settings on the QPrinter and * call print again. * The printjob can thus see startPrinting() called more than once, and the implementation * of that signal should honor the removePolicy passed to it. */ class KRITAUI_EXPORT KisPrintJob : public QObject { Q_OBJECT public: /** * Constructor. - * @param parent the parent qobject that is passed for memory management purposes. + * @param image the image that is passed for management purposes. */ explicit KisPrintJob(KisImageWSP image); ~KisPrintJob() override; /// A policy to allow the printjob to delete itself after its done printing. enum RemovePolicy { DeleteWhenDone, ///< Delete the job when its done with printing. DoNotDelete ///< Keep the job around so it can be started again. }; /// Returns the printer that is used for this print job so others can alter the details of the print-job. QPrinter &printer() { return m_printer; } int documentFirstPage() const { return 1; } int documentLastPage() const { return 1; } int documentCurrentPage() const { return 1; } QAbstractPrintDialog::PrintDialogOptions printDialogOptions() const; /** *@brief Check if the painter can print to the printer *@returns true if the print job can print to the given printer */ bool canPrint(); public Q_SLOTS: /** * This is called every time the job should be executed. * When called the document should be printed a new painter using the printer * of this printJob in order to honor the settings the user made on the printer. * canPrint() should be called before startPrinting to check if the painter can print * to the printer * @param removePolicy a policy that should be honored so the caller can make sure * this job doesn't leak memory after being used. */ void startPrinting(RemovePolicy removePolicy = DoNotDelete); private: KisImageWSP m_image; QPrinter m_printer; }; #endif diff --git a/libs/ui/KisResourceBundle.h b/libs/ui/KisResourceBundle.h index 43db4e25e9..b223b7baba 100644 --- a/libs/ui/KisResourceBundle.h +++ b/libs/ui/KisResourceBundle.h @@ -1,162 +1,165 @@ /* * Copyright (c) 2014 Victor Lafon metabolic.ewilan@hotmail.fr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KORESOURCEBUNDLE_H #define KORESOURCEBUNDLE_H #include #include #include #include #include "KisResourceBundleManifest.h" #include "kritaui_export.h" class KoStore; /** * @brief The ResourceBundle class * @details Describe the resource bundles as KoResources */ class KRITAUI_EXPORT KisResourceBundle : public KoResource { public: /** - * @brief ResourceBundle : Ctor * @param bundlePath the path of the bundle + * @brief ResourceBundle : Ctor * + * @param fileName the path of the bundle */ KisResourceBundle(QString const& fileName); /** * @brief ~ResourceBundle : Dtor */ ~KisResourceBundle() override; /** * @brief defaultFileExtension * @return the default file extension which should be when saving the resource */ QString defaultFileExtension() const override; /** * @brief load : Load this resource. * @return true if succeed, false otherwise. */ bool load() override; bool loadFromDevice(QIODevice *dev) override; /** * @brief save : Save this resource. * @return true if succeed, false otherwise. */ bool save() override; bool saveToDevice(QIODevice* dev) const override; /** * @brief install : Install the contents of the resource bundle. */ bool install(); /** * @brief uninstall : Uninstall the resource bundle. */ bool uninstall(); /** * @brief addMeta : Add a Metadata to the resource * @param type type of the metadata * @param value value of the metadata */ void addMeta(const QString &type, const QString &value); const QString getMeta(const QString &type, const QString &defaultValue = QString()) const; /** - * @brief addFile : Add a file to the bundle + * @brief Add a file to the bundle * @param fileType type of the resource file * @param filePath path of the resource file + * @param fileTagList the list of tags + * @param md5sum the file MD5 checksum */ void addResource(QString fileType, QString filePath, QStringList fileTagList, const QByteArray md5sum); QList getTagsList(); /** * @brief isInstalled * @return true if the bundle is installed, false otherwise. */ bool isInstalled(); /** * @brief setInstalled * This allows you to set installed or uninstalled upon loading. This is used with blacklists. */ void setInstalled(bool install); void setThumbnail(QString); /** * @brief saveMetadata: saves bundle metadata * @param store bundle where to save the metadata */ void saveMetadata(QScopedPointer &store); /** * @brief saveManifest: saves bundle manifest * @param store bundle where to save the manifest */ void saveManifest(QScopedPointer &store); /** * @brief recreateBundle * It recreates the bundle by copying the old bundle information to a new store * and recalculating the md5 of each resource. * @param oldStore the old store to be recreated. */ void recreateBundle(QScopedPointer &oldStore); QStringList resourceTypes() const; QList resources(const QString &resType = QString()) const; int resourceCount() const; private: void writeMeta(const char *metaTag, const QString &metaKey, KoXmlWriter *writer); void writeUserDefinedMeta(const QString &metaKey, KoXmlWriter *writer); private: QImage m_thumbnail; KisResourceBundleManifest m_manifest; QMap m_metadata; QSet m_bundletags; bool m_installed; QList m_gradientsMd5Installed; QList m_patternsMd5Installed; QList m_brushesMd5Installed; QList m_palettesMd5Installed; QList m_workspacesMd5Installed; QList m_presetsMd5Installed; QList m_gamutMasksMd5Installed; QString m_bundleVersion; }; typedef QSharedPointer KisResourceBundleSP; #endif // KORESOURCEBUNDLE_H diff --git a/libs/ui/KisResourceBundleManifest.h b/libs/ui/KisResourceBundleManifest.h index 3351b99dea..c854f88d51 100644 --- a/libs/ui/KisResourceBundleManifest.h +++ b/libs/ui/KisResourceBundleManifest.h @@ -1,100 +1,100 @@ /* This file is part of the KDE project Copyright (C) 2014, Victor Lafon This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #ifndef KOXMLRESOURCEBUNDLEMANIFEST_H #define KOXMLRESOURCEBUNDLEMANIFEST_H #include #include #include #include #include class QIODevice; class KRITAUI_EXPORT KisResourceBundleManifest { public: struct ResourceReference { ResourceReference(const QString &_resourcePath, const QList &_tagList, const QString &_fileTypeName, const QByteArray &_md5) { resourcePath = _resourcePath; tagList = _tagList; fileTypeName = _fileTypeName; md5sum = _md5; } QString resourcePath; QList tagList; QString fileTypeName; QByteArray md5sum; }; /** * @brief ResourceBundleManifest : Ctor - * @param xmlName the name of the XML file to be created */ KisResourceBundleManifest(); /** * @brief ~ResourceBundleManifest : Dtor */ virtual ~KisResourceBundleManifest(); /** * @brief load the ResourceBundleManifest from the given device */ bool load(QIODevice *device); /** * @brief save the ResourceBundleManifest to the given device */ bool save(QIODevice *device); /** * @brief addTag : Add a file tag as a child of the fileType tag. * @param fileType the type of the file to be added * @param fileName the name of the file to be added - * @param emptyFile true if the file is empty + * @param tagFileList list of the tags + * @param md5 MD5 checksum * @return the element corresponding to the created tag. */ void addResource(const QString &fileType, const QString &fileName, const QStringList &tagFileList, const QByteArray &md5); QStringList types() const; QStringList tags() const; QList files(const QString &type = QString()) const; /** * @brief removeFile : remove a file from the manifest * @param fileName : the name of the file to be removed * @return the list of resource tags to be removed from meta file. */ void removeFile(QString fileName); private: QMap > m_resources; }; #endif // KOXMLRESOURCEBUNDLEMANIFEST_H diff --git a/libs/ui/KisSaveGroupVisitor.h b/libs/ui/KisSaveGroupVisitor.h index 6e4323ec50..47fccb7d53 100644 --- a/libs/ui/KisSaveGroupVisitor.h +++ b/libs/ui/KisSaveGroupVisitor.h @@ -1,103 +1,103 @@ /* * Copyright (C) 2016 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KISSAVEGROUPVISITOR_H #define KISSAVEGROUPVISITOR_H #include "kritaui_export.h" #include #include #include #include #include #include #include #include /** * @brief The KisSaveGroupVisitor class saves the groups in * a Krita image to separate images. */ class KRITAUI_EXPORT KisSaveGroupVisitor : public KisNodeVisitor { public: /** * Create a KisSaveGroupVisitor * * @param image: the image to save * @param saveInvisible: also save invisible layers * @param saveTopLevelOnly: if true, only save the toplevel layers, otherwise * descend into groups and save the bottom-most groups (groups that do * not contain another group. - * @param url the base location where the images will be saved + * @param path the base location where the images will be saved * @param baseName the basename of the images * @param extension the file format extension * @param mimeFilter the export image type */ KisSaveGroupVisitor(KisImageWSP image, bool saveInvisible, bool saveTopLevelOnly, const QString &path, const QString &baseName, const QString &extension, const QString &mimeFilter); ~KisSaveGroupVisitor() override; public: bool visit(KisNode* ) override; bool visit(KisPaintLayer *) override; bool visit(KisAdjustmentLayer *) override; bool visit(KisExternalLayer *) override; bool visit(KisCloneLayer *) override; bool visit(KisFilterMask *) override; bool visit(KisTransformMask *) override; bool visit(KisTransparencyMask *) override; bool visit(KisGeneratorLayer * ) override; bool visit(KisSelectionMask* ) override; bool visit(KisColorizeMask* ) override; bool visit(KisGroupLayer *layer) override; private: KisImageWSP m_image; bool m_saveInvisible; bool m_saveTopLevelOnly; QString m_path; QString m_baseName; QString m_extension; QString m_mimeFilter; }; #endif // KISSAVEGROUPVISITOR_H diff --git a/libs/ui/KisViewManager.cpp b/libs/ui/KisViewManager.cpp index 7ab68dc6df..af33717542 100644 --- a/libs/ui/KisViewManager.cpp +++ b/libs/ui/KisViewManager.cpp @@ -1,1443 +1,1442 @@ /* * This file is part of KimageShop^WKrayon^WKrita * * Copyright (c) 1999 Matthias Elter * 1999 Michael Koch * 1999 Carsten Pfeiffer * 2002 Patrick Julien * 2003-2011 Boudewijn Rempt * 2004 Clarence Dang * 2011 José Luis Vergara * 2017 L. E. Segovia * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 "KisViewManager.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 #include #include #include #include #include #include #include #include #include #include #include #include "input/kis_input_manager.h" #include "canvas/kis_canvas2.h" #include "canvas/kis_canvas_controller.h" #include "canvas/kis_grid_manager.h" #include "dialogs/kis_dlg_blacklist_cleanup.h" #include "input/kis_input_profile_manager.h" #include "kis_action_manager.h" #include "kis_action.h" #include "kis_canvas_controls_manager.h" #include "kis_canvas_resource_provider.h" #include "kis_composite_progress_proxy.h" #include #include "kis_config.h" #include "kis_config_notifier.h" #include "kis_control_frame.h" #include "kis_coordinates_converter.h" #include "KisDocument.h" #include "kis_favorite_resource_manager.h" #include "kis_filter_manager.h" #include "kis_group_layer.h" #include #include #include "kis_image_manager.h" #include #include "kis_mainwindow_observer.h" #include "kis_mask_manager.h" #include "kis_mimedata.h" #include "kis_mirror_manager.h" #include "kis_node_commands_adapter.h" #include "kis_node.h" #include "kis_node_manager.h" #include "KisDecorationsManager.h" #include #include "kis_paintop_box.h" #include #include "KisPart.h" #include "KisPrintJob.h" #include #include "KisResourceServerProvider.h" #include "kis_selection.h" #include "kis_selection_mask.h" #include "kis_selection_manager.h" #include "kis_shape_controller.h" #include "kis_shape_layer.h" #include #include "kis_statusbar.h" #include #include #include "kis_tooltip_manager.h" #include #include "KisView.h" #include "kis_zoom_manager.h" #include "widgets/kis_floating_message.h" #include "kis_signal_auto_connection.h" #include "kis_icon_utils.h" #include "kis_guides_manager.h" #include "kis_derived_resources.h" #include "dialogs/kis_delayed_save_dialog.h" #include #include "kis_signals_blocker.h" class BlockingUserInputEventFilter : public QObject { bool eventFilter(QObject *watched, QEvent *event) override { Q_UNUSED(watched); if(dynamic_cast(event) || dynamic_cast(event) || dynamic_cast(event)) { return true; } else { return false; } } }; class KisViewManager::KisViewManagerPrivate { public: KisViewManagerPrivate(KisViewManager *_q, KActionCollection *_actionCollection, QWidget *_q_parent) : filterManager(_q) , createTemplate(0) , saveIncremental(0) , saveIncrementalBackup(0) , openResourcesDirectory(0) , rotateCanvasRight(0) , rotateCanvasLeft(0) , resetCanvasRotation(0) , wrapAroundAction(0) , levelOfDetailAction(0) , showRulersAction(0) , rulersTrackMouseAction(0) , zoomTo100pct(0) , zoomIn(0) , zoomOut(0) , selectionManager(_q) , statusBar(_q) , controlFrame(_q, _q_parent) , nodeManager(_q) , imageManager(_q) , gridManager(_q) , canvasControlsManager(_q) , paintingAssistantsManager(_q) , actionManager(_q, _actionCollection) , mainWindow(0) , showFloatingMessage(true) , currentImageView(0) , canvasResourceProvider(_q) , canvasResourceManager() , guiUpdateCompressor(30, KisSignalCompressor::POSTPONE, _q) , actionCollection(_actionCollection) , mirrorManager(_q) , inputManager(_q) , actionAuthor(0) , showPixelGrid(0) { KisViewManager::initializeResourceManager(&canvasResourceManager); } public: KisFilterManager filterManager; KisAction *createTemplate; KisAction *createCopy; KisAction *saveIncremental; KisAction *saveIncrementalBackup; KisAction *openResourcesDirectory; KisAction *rotateCanvasRight; KisAction *rotateCanvasLeft; KisAction *resetCanvasRotation; KisAction *wrapAroundAction; KisAction *levelOfDetailAction; KisAction *showRulersAction; KisAction *rulersTrackMouseAction; KisAction *zoomTo100pct; KisAction *zoomIn; KisAction *zoomOut; KisAction *softProof; KisAction *gamutCheck; KisAction *toggleFgBg; KisAction *resetFgBg; KisSelectionManager selectionManager; KisGuidesManager guidesManager; KisStatusBar statusBar; QPointer persistentImageProgressUpdater; QScopedPointer persistentUnthreadedProgressUpdaterRouter; QPointer persistentUnthreadedProgressUpdater; KisControlFrame controlFrame; KisNodeManager nodeManager; KisImageManager imageManager; KisGridManager gridManager; KisCanvasControlsManager canvasControlsManager; KisDecorationsManager paintingAssistantsManager; BlockingUserInputEventFilter blockingEventFilter; KisActionManager actionManager; QMainWindow* mainWindow; QPointer savedFloatingMessage; bool showFloatingMessage; QPointer currentImageView; KisCanvasResourceProvider canvasResourceProvider; KoCanvasResourceProvider canvasResourceManager; KisSignalCompressor guiUpdateCompressor; KActionCollection *actionCollection; KisMirrorManager mirrorManager; KisInputManager inputManager; KisSignalAutoConnectionsStore viewConnections; KSelectAction *actionAuthor; // Select action for author profile. KisAction *showPixelGrid; QByteArray canvasState; #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) QFlags windowFlags; #endif bool blockUntilOperationsFinishedImpl(KisImageSP image, bool force); }; KisViewManager::KisViewManager(QWidget *parent, KActionCollection *_actionCollection) : d(new KisViewManagerPrivate(this, _actionCollection, parent)) { d->actionCollection = _actionCollection; d->mainWindow = dynamic_cast(parent); d->canvasResourceProvider.setResourceManager(&d->canvasResourceManager); connect(&d->guiUpdateCompressor, SIGNAL(timeout()), this, SLOT(guiUpdateTimeout())); createActions(); setupManagers(); // These initialization functions must wait until KisViewManager ctor is complete. d->statusBar.setup(); d->persistentImageProgressUpdater = d->statusBar.progressUpdater()->startSubtask(1, "", true); // reset state to "completed" d->persistentImageProgressUpdater->setRange(0,100); d->persistentImageProgressUpdater->setValue(100); d->persistentUnthreadedProgressUpdater = d->statusBar.progressUpdater()->startSubtask(1, "", true); // reset state to "completed" d->persistentUnthreadedProgressUpdater->setRange(0,100); d->persistentUnthreadedProgressUpdater->setValue(100); d->persistentUnthreadedProgressUpdaterRouter.reset( new KoProgressUpdater(d->persistentUnthreadedProgressUpdater, KoProgressUpdater::Unthreaded)); d->persistentUnthreadedProgressUpdaterRouter->setAutoNestNames(true); d->controlFrame.setup(parent); //Check to draw scrollbars after "Canvas only mode" toggle is created. this->showHideScrollbars(); QScopedPointer dummy(new KoDummyCanvasController(actionCollection())); KoToolManager::instance()->registerToolActions(actionCollection(), dummy.data()); QTimer::singleShot(0, this, SLOT(initializeStatusBarVisibility())); connect(KoToolManager::instance(), SIGNAL(inputDeviceChanged(KoInputDevice)), d->controlFrame.paintopBox(), SLOT(slotInputDeviceChanged(KoInputDevice))); connect(KoToolManager::instance(), SIGNAL(changedTool(KoCanvasController*,int)), d->controlFrame.paintopBox(), SLOT(slotToolChanged(KoCanvasController*,int))); connect(&d->nodeManager, SIGNAL(sigNodeActivated(KisNodeSP)), resourceProvider(), SLOT(slotNodeActivated(KisNodeSP))); connect(KisPart::instance(), SIGNAL(sigViewAdded(KisView*)), SLOT(slotViewAdded(KisView*))); connect(KisPart::instance(), SIGNAL(sigViewRemoved(KisView*)), SLOT(slotViewRemoved(KisView*))); connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotUpdateAuthorProfileActions())); connect(KisConfigNotifier::instance(), SIGNAL(pixelGridModeChanged()), SLOT(slotUpdatePixelGridAction())); KisInputProfileManager::instance()->loadProfiles(); KisConfig cfg(true); d->showFloatingMessage = cfg.showCanvasMessages(); const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8(); KoColor foreground(Qt::black, cs); d->canvasResourceProvider.setFGColor(cfg.readKoColor("LastForeGroundColor",foreground)); KoColor background(Qt::white, cs); d->canvasResourceProvider.setBGColor(cfg.readKoColor("LastBackGroundColor",background)); - - - } KisViewManager::~KisViewManager() { KisConfig cfg(false); if (resourceProvider() && resourceProvider()->currentPreset()) { cfg.writeKoColor("LastForeGroundColor",resourceProvider()->fgColor()); cfg.writeKoColor("LastBackGroundColor",resourceProvider()->bgColor()); } cfg.writeEntry("baseLength", KoResourceItemChooserSync::instance()->baseLength()); - + cfg.writeEntry("CanvasOnlyActive", false); // We never restart in CavnasOnlyMode delete d; } void KisViewManager::initializeResourceManager(KoCanvasResourceProvider *resourceManager) { resourceManager->addDerivedResourceConverter(toQShared(new KisCompositeOpResourceConverter)); resourceManager->addDerivedResourceConverter(toQShared(new KisEffectiveCompositeOpResourceConverter)); resourceManager->addDerivedResourceConverter(toQShared(new KisOpacityResourceConverter)); resourceManager->addDerivedResourceConverter(toQShared(new KisFlowResourceConverter)); resourceManager->addDerivedResourceConverter(toQShared(new KisSizeResourceConverter)); resourceManager->addDerivedResourceConverter(toQShared(new KisLodAvailabilityResourceConverter)); resourceManager->addDerivedResourceConverter(toQShared(new KisLodSizeThresholdResourceConverter)); resourceManager->addDerivedResourceConverter(toQShared(new KisLodSizeThresholdSupportedResourceConverter)); resourceManager->addDerivedResourceConverter(toQShared(new KisEraserModeResourceConverter)); resourceManager->addResourceUpdateMediator(toQShared(new KisPresetUpdateMediator)); } KActionCollection *KisViewManager::actionCollection() const { return d->actionCollection; } void KisViewManager::slotViewAdded(KisView *view) { // WARNING: this slot is called even when a view from another main windows is added! // Don't expect \p view be a child of this view manager! Q_UNUSED(view); if (viewCount() == 0) { d->statusBar.showAllStatusBarItems(); } } void KisViewManager::slotViewRemoved(KisView *view) { // WARNING: this slot is called even when a view from another main windows is removed! // Don't expect \p view be a child of this view manager! Q_UNUSED(view); if (viewCount() == 0) { d->statusBar.hideAllStatusBarItems(); } KisConfig cfg(false); if (resourceProvider() && resourceProvider()->currentPreset()) { cfg.writeEntry("LastPreset", resourceProvider()->currentPreset()->name()); } } void KisViewManager::setCurrentView(KisView *view) { bool first = true; if (d->currentImageView) { d->currentImageView->notifyCurrentStateChanged(false); d->currentImageView->canvasBase()->setCursor(QCursor(Qt::ArrowCursor)); first = false; KisDocument* doc = d->currentImageView->document(); if (doc) { doc->image()->compositeProgressProxy()->removeProxy(d->persistentImageProgressUpdater); doc->disconnect(this); } d->currentImageView->canvasController()->proxyObject->disconnect(&d->statusBar); d->viewConnections.clear(); } QPointer imageView = qobject_cast(view); d->currentImageView = imageView; if (imageView) { d->softProof->setChecked(imageView->softProofing()); d->gamutCheck->setChecked(imageView->gamutCheck()); // Wait for the async image to have loaded KisDocument* doc = view->document(); if (KisConfig(true).readEntry("EnablePositionLabel", false)) { connect(d->currentImageView->canvasController()->proxyObject, SIGNAL(documentMousePositionChanged(QPointF)), &d->statusBar, SLOT(documentMousePositionChanged(QPointF))); } // Restore the last used brush preset, color and background color. if (first) { KisPaintOpPresetResourceServer * rserver = KisResourceServerProvider::instance()->paintOpPresetServer(); QString defaultPresetName = "basic_tip_default"; bool foundTip = false; for (int i=0; iresourceCount(); i++) { KisPaintOpPresetSP resource = rserver->resources().at(i); if (resource->name().toLower().contains("basic_tip_default")) { defaultPresetName = resource->name(); foundTip = true; } else if (foundTip == false && (resource->name().toLower().contains("default") || resource->filename().toLower().contains("default"))) { defaultPresetName = resource->name(); foundTip = true; } } KisConfig cfg(true); QString lastPreset = cfg.readEntry("LastPreset", defaultPresetName); KisPaintOpPresetSP preset = rserver->resourceByName(lastPreset); if (!preset) { preset = rserver->resourceByName(defaultPresetName); } if (!preset && !rserver->resources().isEmpty()) { preset = rserver->resources().first(); } if (preset) { paintOpBox()->restoreResource(preset); } } KisCanvasController *canvasController = dynamic_cast(d->currentImageView->canvasController()); d->viewConnections.addUniqueConnection(&d->nodeManager, SIGNAL(sigNodeActivated(KisNodeSP)), doc->image(), SLOT(requestStrokeEndActiveNode())); d->viewConnections.addUniqueConnection(d->rotateCanvasRight, SIGNAL(triggered()), canvasController, SLOT(rotateCanvasRight15())); d->viewConnections.addUniqueConnection(d->rotateCanvasLeft, SIGNAL(triggered()),canvasController, SLOT(rotateCanvasLeft15())); d->viewConnections.addUniqueConnection(d->resetCanvasRotation, SIGNAL(triggered()),canvasController, SLOT(resetCanvasRotation())); d->viewConnections.addUniqueConnection(d->wrapAroundAction, SIGNAL(toggled(bool)), canvasController, SLOT(slotToggleWrapAroundMode(bool))); d->wrapAroundAction->setChecked(canvasController->wrapAroundMode()); d->viewConnections.addUniqueConnection(d->levelOfDetailAction, SIGNAL(toggled(bool)), canvasController, SLOT(slotToggleLevelOfDetailMode(bool))); d->levelOfDetailAction->setChecked(canvasController->levelOfDetailMode()); d->viewConnections.addUniqueConnection(d->currentImageView->image(), SIGNAL(sigColorSpaceChanged(const KoColorSpace*)), d->controlFrame.paintopBox(), SLOT(slotColorSpaceChanged(const KoColorSpace*))); d->viewConnections.addUniqueConnection(d->showRulersAction, SIGNAL(toggled(bool)), imageView->zoomManager(), SLOT(setShowRulers(bool))); d->viewConnections.addUniqueConnection(d->rulersTrackMouseAction, SIGNAL(toggled(bool)), imageView->zoomManager(), SLOT(setRulersTrackMouse(bool))); d->viewConnections.addUniqueConnection(d->zoomTo100pct, SIGNAL(triggered()), imageView->zoomManager(), SLOT(zoomTo100())); d->viewConnections.addUniqueConnection(d->zoomIn, SIGNAL(triggered()), imageView->zoomController()->zoomAction(), SLOT(zoomIn())); d->viewConnections.addUniqueConnection(d->zoomOut, SIGNAL(triggered()), imageView->zoomController()->zoomAction(), SLOT(zoomOut())); d->viewConnections.addUniqueConnection(d->softProof, SIGNAL(toggled(bool)), view, SLOT(slotSoftProofing(bool)) ); d->viewConnections.addUniqueConnection(d->gamutCheck, SIGNAL(toggled(bool)), view, SLOT(slotGamutCheck(bool)) ); // set up progrress reporting doc->image()->compositeProgressProxy()->addProxy(d->persistentImageProgressUpdater); d->viewConnections.addUniqueConnection(&d->statusBar, SIGNAL(sigCancellationRequested()), doc->image(), SLOT(requestStrokeCancellation())); d->viewConnections.addUniqueConnection(d->showPixelGrid, SIGNAL(toggled(bool)), canvasController, SLOT(slotTogglePixelGrid(bool))); imageView->zoomManager()->setShowRulers(d->showRulersAction->isChecked()); imageView->zoomManager()->setRulersTrackMouse(d->rulersTrackMouseAction->isChecked()); showHideScrollbars(); } d->filterManager.setView(imageView); d->selectionManager.setView(imageView); d->guidesManager.setView(imageView); d->nodeManager.setView(imageView); d->imageManager.setView(imageView); d->canvasControlsManager.setView(imageView); d->actionManager.setView(imageView); d->gridManager.setView(imageView); d->statusBar.setView(imageView); d->paintingAssistantsManager.setView(imageView); d->mirrorManager.setView(imageView); if (d->currentImageView) { d->currentImageView->notifyCurrentStateChanged(true); d->currentImageView->canvasController()->activate(); d->currentImageView->canvasController()->setFocus(); d->viewConnections.addUniqueConnection( image(), SIGNAL(sigSizeChanged(QPointF,QPointF)), resourceProvider(), SLOT(slotImageSizeChanged())); d->viewConnections.addUniqueConnection( image(), SIGNAL(sigResolutionChanged(double,double)), resourceProvider(), SLOT(slotOnScreenResolutionChanged())); d->viewConnections.addUniqueConnection( image(), SIGNAL(sigNodeChanged(KisNodeSP)), this, SLOT(updateGUI())); d->viewConnections.addUniqueConnection( d->currentImageView->zoomManager()->zoomController(), SIGNAL(zoomChanged(KoZoomMode::Mode,qreal)), resourceProvider(), SLOT(slotOnScreenResolutionChanged())); } d->actionManager.updateGUI(); resourceProvider()->slotImageSizeChanged(); resourceProvider()->slotOnScreenResolutionChanged(); Q_EMIT viewChanged(); } KoZoomController *KisViewManager::zoomController() const { if (d->currentImageView) { return d->currentImageView->zoomController(); } return 0; } KisImageWSP KisViewManager::image() const { if (document()) { return document()->image(); } return 0; } KisCanvasResourceProvider * KisViewManager::resourceProvider() { return &d->canvasResourceProvider; } KisCanvas2 * KisViewManager::canvasBase() const { if (d && d->currentImageView) { return d->currentImageView->canvasBase(); } return 0; } QWidget* KisViewManager::canvas() const { if (d && d->currentImageView && d->currentImageView->canvasBase()->canvasWidget()) { return d->currentImageView->canvasBase()->canvasWidget(); } return 0; } KisStatusBar * KisViewManager::statusBar() const { return &d->statusBar; } KisPaintopBox* KisViewManager::paintOpBox() const { return d->controlFrame.paintopBox(); } QPointer KisViewManager::createUnthreadedUpdater(const QString &name) { return d->persistentUnthreadedProgressUpdaterRouter->startSubtask(1, name, false); } QPointer KisViewManager::createThreadedUpdater(const QString &name) { return d->statusBar.progressUpdater()->startSubtask(1, name, false); } KisSelectionManager * KisViewManager::selectionManager() { return &d->selectionManager; } KisNodeSP KisViewManager::activeNode() { return d->nodeManager.activeNode(); } KisLayerSP KisViewManager::activeLayer() { return d->nodeManager.activeLayer(); } KisPaintDeviceSP KisViewManager::activeDevice() { return d->nodeManager.activePaintDevice(); } KisZoomManager * KisViewManager::zoomManager() { if (d->currentImageView) { return d->currentImageView->zoomManager(); } return 0; } KisFilterManager * KisViewManager::filterManager() { return &d->filterManager; } KisImageManager * KisViewManager::imageManager() { return &d->imageManager; } KisInputManager* KisViewManager::inputManager() const { return &d->inputManager; } KisSelectionSP KisViewManager::selection() { if (d->currentImageView) { return d->currentImageView->selection(); } return 0; } bool KisViewManager::selectionEditable() { KisLayerSP layer = activeLayer(); if (layer) { KisSelectionMaskSP mask = layer->selectionMask(); if (mask) { return mask->isEditable(); } } // global selection is always editable return true; } KisUndoAdapter * KisViewManager::undoAdapter() { if (!document()) return 0; KisImageWSP image = document()->image(); Q_ASSERT(image); return image->undoAdapter(); } void KisViewManager::createActions() { KisConfig cfg(true); d->saveIncremental = actionManager()->createAction("save_incremental_version"); connect(d->saveIncremental, SIGNAL(triggered()), this, SLOT(slotSaveIncremental())); d->saveIncrementalBackup = actionManager()->createAction("save_incremental_backup"); connect(d->saveIncrementalBackup, SIGNAL(triggered()), this, SLOT(slotSaveIncrementalBackup())); connect(mainWindow(), SIGNAL(documentSaved()), this, SLOT(slotDocumentSaved())); d->saveIncremental->setEnabled(false); d->saveIncrementalBackup->setEnabled(false); KisAction *tabletDebugger = actionManager()->createAction("tablet_debugger"); connect(tabletDebugger, SIGNAL(triggered()), this, SLOT(toggleTabletLogger())); d->createTemplate = actionManager()->createAction("create_template"); connect(d->createTemplate, SIGNAL(triggered()), this, SLOT(slotCreateTemplate())); d->createCopy = actionManager()->createAction("create_copy"); connect(d->createCopy, SIGNAL(triggered()), this, SLOT(slotCreateCopy())); d->openResourcesDirectory = actionManager()->createAction("open_resources_directory"); connect(d->openResourcesDirectory, SIGNAL(triggered()), SLOT(openResourcesDirectory())); d->rotateCanvasRight = actionManager()->createAction("rotate_canvas_right"); d->rotateCanvasLeft = actionManager()->createAction("rotate_canvas_left"); d->resetCanvasRotation = actionManager()->createAction("reset_canvas_rotation"); d->wrapAroundAction = actionManager()->createAction("wrap_around_mode"); d->levelOfDetailAction = actionManager()->createAction("level_of_detail_mode"); d->softProof = actionManager()->createAction("softProof"); d->gamutCheck = actionManager()->createAction("gamutCheck"); KisAction *tAction = actionManager()->createAction("showStatusBar"); tAction->setChecked(cfg.showStatusBar()); connect(tAction, SIGNAL(toggled(bool)), this, SLOT(showStatusBar(bool))); tAction = actionManager()->createAction("view_show_canvas_only"); tAction->setChecked(false); connect(tAction, SIGNAL(toggled(bool)), this, SLOT(switchCanvasOnly(bool))); //Workaround, by default has the same shortcut as mirrorCanvas KisAction *a = dynamic_cast(actionCollection()->action("format_italic")); if (a) { a->setDefaultShortcut(QKeySequence()); } a = actionManager()->createAction("edit_blacklist_cleanup"); connect(a, SIGNAL(triggered()), this, SLOT(slotBlacklistCleanup())); actionManager()->createAction("ruler_pixel_multiple2"); d->showRulersAction = actionManager()->createAction("view_ruler"); d->showRulersAction->setChecked(cfg.showRulers()); connect(d->showRulersAction, SIGNAL(toggled(bool)), SLOT(slotSaveShowRulersState(bool))); d->rulersTrackMouseAction = actionManager()->createAction("rulers_track_mouse"); d->rulersTrackMouseAction->setChecked(cfg.rulersTrackMouse()); connect(d->rulersTrackMouseAction, SIGNAL(toggled(bool)), SLOT(slotSaveRulersTrackMouseState(bool))); d->zoomTo100pct = actionManager()->createAction("zoom_to_100pct"); d->zoomIn = actionManager()->createStandardAction(KStandardAction::ZoomIn, 0, ""); d->zoomOut = actionManager()->createStandardAction(KStandardAction::ZoomOut, 0, ""); d->actionAuthor = new KSelectAction(KisIconUtils::loadIcon("im-user"), i18n("Active Author Profile"), this); connect(d->actionAuthor, SIGNAL(triggered(QString)), this, SLOT(changeAuthorProfile(QString))); actionCollection()->addAction("settings_active_author", d->actionAuthor); slotUpdateAuthorProfileActions(); d->showPixelGrid = actionManager()->createAction("view_pixel_grid"); slotUpdatePixelGridAction(); d->toggleFgBg = actionManager()->createAction("toggle_fg_bg"); connect(d->toggleFgBg, SIGNAL(triggered(bool)), this, SLOT(slotToggleFgBg())); d->resetFgBg = actionManager()->createAction("reset_fg_bg"); connect(d->resetFgBg, SIGNAL(triggered(bool)), this, SLOT(slotResetFgBg())); } void KisViewManager::setupManagers() { // Create the managers for filters, selections, layers etc. // XXX: When the currentlayer changes, call updateGUI on all // managers d->filterManager.setup(actionCollection(), actionManager()); d->selectionManager.setup(actionManager()); d->guidesManager.setup(actionManager()); d->nodeManager.setup(actionCollection(), actionManager()); d->imageManager.setup(actionManager()); d->gridManager.setup(actionManager()); d->paintingAssistantsManager.setup(actionManager()); d->canvasControlsManager.setup(actionManager()); d->mirrorManager.setup(actionCollection()); } void KisViewManager::updateGUI() { d->guiUpdateCompressor.start(); } void KisViewManager::slotBlacklistCleanup() { KisDlgBlacklistCleanup dialog; dialog.exec(); } KisNodeManager * KisViewManager::nodeManager() const { return &d->nodeManager; } KisActionManager* KisViewManager::actionManager() const { return &d->actionManager; } KisGridManager * KisViewManager::gridManager() const { return &d->gridManager; } KisGuidesManager * KisViewManager::guidesManager() const { return &d->guidesManager; } KisDocument *KisViewManager::document() const { if (d->currentImageView && d->currentImageView->document()) { return d->currentImageView->document(); } return 0; } int KisViewManager::viewCount() const { KisMainWindow *mw = qobject_cast(d->mainWindow); if (mw) { return mw->viewCount(); } return 0; } bool KisViewManager::KisViewManagerPrivate::blockUntilOperationsFinishedImpl(KisImageSP image, bool force) { const int busyWaitDelay = 1000; KisDelayedSaveDialog dialog(image, !force ? KisDelayedSaveDialog::GeneralDialog : KisDelayedSaveDialog::ForcedDialog, busyWaitDelay, mainWindow); dialog.blockIfImageIsBusy(); return dialog.result() == QDialog::Accepted; } bool KisViewManager::blockUntilOperationsFinished(KisImageSP image) { return d->blockUntilOperationsFinishedImpl(image, false); } void KisViewManager::blockUntilOperationsFinishedForced(KisImageSP image) { d->blockUntilOperationsFinishedImpl(image, true); } void KisViewManager::slotCreateTemplate() { if (!document()) return; KisTemplateCreateDia::createTemplate( QStringLiteral("templates/"), ".kra", document(), mainWindow()); } void KisViewManager::slotCreateCopy() { KisDocument *srcDoc = document(); if (!srcDoc) return; if (!this->blockUntilOperationsFinished(srcDoc->image())) return; KisDocument *doc = 0; { KisImageBarrierLocker l(srcDoc->image()); doc = srcDoc->clone(); } KIS_SAFE_ASSERT_RECOVER_RETURN(doc); QString name = srcDoc->documentInfo()->aboutInfo("name"); if (name.isEmpty()) { name = document()->url().toLocalFile(); } name = i18n("%1 (Copy)", name); doc->documentInfo()->setAboutInfo("title", name); KisPart::instance()->addDocument(doc); KisMainWindow *mw = qobject_cast(d->mainWindow); mw->addViewAndNotifyLoadingCompleted(doc); } QMainWindow* KisViewManager::qtMainWindow() const { if (d->mainWindow) return d->mainWindow; //Fallback for when we have not yet set the main window. QMainWindow* w = qobject_cast(qApp->activeWindow()); if(w) return w; return mainWindow(); } void KisViewManager::setQtMainWindow(QMainWindow* newMainWindow) { d->mainWindow = newMainWindow; } void KisViewManager::slotDocumentSaved() { d->saveIncremental->setEnabled(true); d->saveIncrementalBackup->setEnabled(true); } void KisViewManager::slotSaveIncremental() { if (!document()) return; if (document()->url().isEmpty()) { KisMainWindow *mw = qobject_cast(d->mainWindow); mw->saveDocument(document(), true, false); return; } bool foundVersion; bool fileAlreadyExists; bool isBackup; QString version = "000"; QString newVersion; QString letter; QString fileName = document()->localFilePath(); // Find current version filenames // v v Regexp to find incremental versions in the filename, taking our backup scheme into account as well // Considering our incremental version and backup scheme, format is filename_001~001.ext QRegExp regex("_\\d{1,4}[.]|_\\d{1,4}[a-z][.]|_\\d{1,4}[~]|_\\d{1,4}[a-z][~]"); regex.indexIn(fileName); // Perform the search QStringList matches = regex.capturedTexts(); foundVersion = matches.at(0).isEmpty() ? false : true; // Ensure compatibility with Save Incremental Backup // If this regex is not kept separate, the entire algorithm needs modification; // It's simpler to just add this. QRegExp regexAux("_\\d{1,4}[~]|_\\d{1,4}[a-z][~]"); regexAux.indexIn(fileName); // Perform the search QStringList matchesAux = regexAux.capturedTexts(); isBackup = matchesAux.at(0).isEmpty() ? false : true; // If the filename has a version, prepare it for incrementation if (foundVersion) { version = matches.at(matches.count() - 1); // Look at the last index, we don't care about other matches if (version.contains(QRegExp("[a-z]"))) { version.chop(1); // Trim "." letter = version.right(1); // Save letter version.chop(1); // Trim letter } else { version.chop(1); // Trim "." } version.remove(0, 1); // Trim "_" } else { // TODO: this will not work with files extensions like jp2 // ...else, simply add a version to it so the next loop works QRegExp regex2("[.][a-z]{2,4}$"); // Heuristic to find file extension regex2.indexIn(fileName); QStringList matches2 = regex2.capturedTexts(); QString extensionPlusVersion = matches2.at(0); extensionPlusVersion.prepend(version); extensionPlusVersion.prepend("_"); fileName.replace(regex2, extensionPlusVersion); } // Prepare the base for new version filename int intVersion = version.toInt(0); ++intVersion; QString baseNewVersion = QString::number(intVersion); while (baseNewVersion.length() < version.length()) { baseNewVersion.prepend("0"); } // Check if the file exists under the new name and search until options are exhausted (test appending a to z) do { newVersion = baseNewVersion; newVersion.prepend("_"); if (!letter.isNull()) newVersion.append(letter); if (isBackup) { newVersion.append("~"); } else { newVersion.append("."); } fileName.replace(regex, newVersion); fileAlreadyExists = QFile(fileName).exists(); if (fileAlreadyExists) { if (!letter.isNull()) { char letterCh = letter.at(0).toLatin1(); ++letterCh; letter = QString(QChar(letterCh)); } else { letter = 'a'; } } } while (fileAlreadyExists && letter != "{"); // x, y, z, {... if (letter == "{") { QMessageBox::critical(mainWindow(), i18nc("@title:window", "Couldn't save incremental version"), i18n("Alternative names exhausted, try manually saving with a higher number")); return; } document()->setFileBatchMode(true); document()->saveAs(QUrl::fromUserInput(fileName), document()->mimeType(), true); document()->setFileBatchMode(false); if (mainWindow()) { mainWindow()->updateCaption(); } } void KisViewManager::slotSaveIncrementalBackup() { if (!document()) return; if (document()->url().isEmpty()) { KisMainWindow *mw = qobject_cast(d->mainWindow); mw->saveDocument(document(), true, false); return; } bool workingOnBackup; bool fileAlreadyExists; QString version = "000"; QString newVersion; QString letter; QString fileName = document()->localFilePath(); // First, discover if working on a backup file, or a normal file QRegExp regex("~\\d{1,4}[.]|~\\d{1,4}[a-z][.]"); regex.indexIn(fileName); // Perform the search QStringList matches = regex.capturedTexts(); workingOnBackup = matches.at(0).isEmpty() ? false : true; if (workingOnBackup) { // Try to save incremental version (of backup), use letter for alt versions version = matches.at(matches.count() - 1); // Look at the last index, we don't care about other matches if (version.contains(QRegExp("[a-z]"))) { version.chop(1); // Trim "." letter = version.right(1); // Save letter version.chop(1); // Trim letter } else { version.chop(1); // Trim "." } version.remove(0, 1); // Trim "~" // Prepare the base for new version filename int intVersion = version.toInt(0); ++intVersion; QString baseNewVersion = QString::number(intVersion); QString backupFileName = document()->localFilePath(); while (baseNewVersion.length() < version.length()) { baseNewVersion.prepend("0"); } // Check if the file exists under the new name and search until options are exhausted (test appending a to z) do { newVersion = baseNewVersion; newVersion.prepend("~"); if (!letter.isNull()) newVersion.append(letter); newVersion.append("."); backupFileName.replace(regex, newVersion); fileAlreadyExists = QFile(backupFileName).exists(); if (fileAlreadyExists) { if (!letter.isNull()) { char letterCh = letter.at(0).toLatin1(); ++letterCh; letter = QString(QChar(letterCh)); } else { letter = 'a'; } } } while (fileAlreadyExists && letter != "{"); // x, y, z, {... if (letter == "{") { QMessageBox::critical(mainWindow(), i18nc("@title:window", "Couldn't save incremental backup"), i18n("Alternative names exhausted, try manually saving with a higher number")); return; } QFile::copy(fileName, backupFileName); document()->saveAs(QUrl::fromUserInput(fileName), document()->mimeType(), true); if (mainWindow()) mainWindow()->updateCaption(); } else { // if NOT working on a backup... // Navigate directory searching for latest backup version, ignore letters const quint8 HARDCODED_DIGIT_COUNT = 3; QString baseNewVersion = "000"; QString backupFileName = document()->localFilePath(); QRegExp regex2("[.][a-z]{2,4}$"); // Heuristic to find file extension regex2.indexIn(backupFileName); QStringList matches2 = regex2.capturedTexts(); QString extensionPlusVersion = matches2.at(0); extensionPlusVersion.prepend(baseNewVersion); extensionPlusVersion.prepend("~"); backupFileName.replace(regex2, extensionPlusVersion); // Save version with 1 number higher than the highest version found ignoring letters do { newVersion = baseNewVersion; newVersion.prepend("~"); newVersion.append("."); backupFileName.replace(regex, newVersion); fileAlreadyExists = QFile(backupFileName).exists(); if (fileAlreadyExists) { // Prepare the base for new version filename, increment by 1 int intVersion = baseNewVersion.toInt(0); ++intVersion; baseNewVersion = QString::number(intVersion); while (baseNewVersion.length() < HARDCODED_DIGIT_COUNT) { baseNewVersion.prepend("0"); } } } while (fileAlreadyExists); // Save both as backup and on current file for interapplication workflow document()->setFileBatchMode(true); QFile::copy(fileName, backupFileName); document()->saveAs(QUrl::fromUserInput(fileName), document()->mimeType(), true); document()->setFileBatchMode(false); if (mainWindow()) mainWindow()->updateCaption(); } } void KisViewManager::disableControls() { // prevents possible crashes, if somebody changes the paintop during dragging by using the mousewheel // this is for Bug 250944 // the solution blocks all wheel, mouse and key event, while dragging with the freehand tool // see KisToolFreehand::initPaint() and endPaint() d->controlFrame.paintopBox()->installEventFilter(&d->blockingEventFilter); Q_FOREACH (QObject* child, d->controlFrame.paintopBox()->children()) { child->installEventFilter(&d->blockingEventFilter); } } void KisViewManager::enableControls() { d->controlFrame.paintopBox()->removeEventFilter(&d->blockingEventFilter); Q_FOREACH (QObject* child, d->controlFrame.paintopBox()->children()) { child->removeEventFilter(&d->blockingEventFilter); } } void KisViewManager::showStatusBar(bool toggled) { KisMainWindow *mw = mainWindow(); if(mw && mw->statusBar()) { mw->statusBar()->setVisible(toggled); KisConfig cfg(false); cfg.setShowStatusBar(toggled); } } void KisViewManager::switchCanvasOnly(bool toggled) { KisConfig cfg(false); - KisMainWindow* main = mainWindow(); + KisMainWindow *main = mainWindow(); if(!main) { dbgUI << "Unable to switch to canvas-only mode, main window not found"; return; } + cfg.writeEntry("CanvasOnlyActive", toggled); + if (toggled) { d->canvasState = qtMainWindow()->saveState(); #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) d->windowFlags = main->windowState(); #endif } if (cfg.hideStatusbarFullscreen()) { if (main->statusBar()) { if (!toggled) { if (main->statusBar()->dynamicPropertyNames().contains("wasvisible")) { if (main->statusBar()->property("wasvisible").toBool()) { main->statusBar()->setVisible(true); } } } else { main->statusBar()->setProperty("wasvisible", main->statusBar()->isVisible()); main->statusBar()->setVisible(false); } } } if (cfg.hideDockersFullscreen()) { KisAction* action = qobject_cast(main->actionCollection()->action("view_toggledockers")); if (action) { action->setCheckable(true); if (toggled) { if (action->isChecked()) { cfg.setShowDockers(action->isChecked()); action->setChecked(false); } else { cfg.setShowDockers(false); } } else { action->setChecked(cfg.showDockers()); } } } // QT in windows does not return to maximized upon 4th tab in a row // https://bugreports.qt.io/browse/QTBUG-57882, https://bugreports.qt.io/browse/QTBUG-52555, https://codereview.qt-project.org/#/c/185016/ if (cfg.hideTitlebarFullscreen() && !cfg.fullscreenMode()) { if(toggled) { main->setWindowState( main->windowState() | Qt::WindowFullScreen); } else { main->setWindowState( main->windowState() & ~Qt::WindowFullScreen); #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) // If window was maximized prior to fullscreen, restore that if (d->windowFlags & Qt::WindowMaximized) { main->setWindowState( main->windowState() | Qt::WindowMaximized); } #endif } } if (cfg.hideMenuFullscreen()) { if (!toggled) { if (main->menuBar()->dynamicPropertyNames().contains("wasvisible")) { if (main->menuBar()->property("wasvisible").toBool()) { main->menuBar()->setVisible(true); } } } else { main->menuBar()->setProperty("wasvisible", main->menuBar()->isVisible()); main->menuBar()->setVisible(false); } } if (cfg.hideToolbarFullscreen()) { QList toolBars = main->findChildren(); Q_FOREACH (QToolBar* toolbar, toolBars) { if (!toggled) { if (toolbar->dynamicPropertyNames().contains("wasvisible")) { if (toolbar->property("wasvisible").toBool()) { toolbar->setVisible(true); } } } else { toolbar->setProperty("wasvisible", toolbar->isVisible()); toolbar->setVisible(false); } } } showHideScrollbars(); if (toggled) { // show a fading heads-up display about the shortcut to go back showFloatingMessage(i18n("Going into Canvas-Only mode.\nPress %1 to go back.", actionCollection()->action("view_show_canvas_only")->shortcut().toString()), QIcon()); } else { main->restoreState(d->canvasState); } } void KisViewManager::toggleTabletLogger() { d->inputManager.toggleTabletLogger(); } void KisViewManager::openResourcesDirectory() { QString dir = KoResourcePaths::locateLocal("data", ""); QDesktopServices::openUrl(QUrl::fromLocalFile(dir)); } void KisViewManager::updateIcons() { if (mainWindow()) { QList dockers = mainWindow()->dockWidgets(); Q_FOREACH (QDockWidget* dock, dockers) { QObjectList objects; objects.append(dock); while (!objects.isEmpty()) { QObject* object = objects.takeFirst(); objects.append(object->children()); KisIconUtils::updateIconCommon(object); } } } } void KisViewManager::initializeStatusBarVisibility() { KisConfig cfg(true); d->mainWindow->statusBar()->setVisible(cfg.showStatusBar()); } void KisViewManager::guiUpdateTimeout() { d->nodeManager.updateGUI(); d->selectionManager.updateGUI(); d->filterManager.updateGUI(); if (zoomManager()) { zoomManager()->updateGUI(); } d->gridManager.updateGUI(); d->actionManager.updateGUI(); } void KisViewManager::showFloatingMessage(const QString &message, const QIcon& icon, int timeout, KisFloatingMessage::Priority priority, int alignment) { if (!d->currentImageView) return; d->currentImageView->showFloatingMessage(message, icon, timeout, priority, alignment); emit floatingMessageRequested(message, icon.name()); } KisMainWindow *KisViewManager::mainWindow() const { return qobject_cast(d->mainWindow); } void KisViewManager::showHideScrollbars() { if (!d->currentImageView) return; if (!d->currentImageView->canvasController()) return; KisConfig cfg(true); bool toggled = actionCollection()->action("view_show_canvas_only")->isChecked(); if ( (toggled && cfg.hideScrollbarsFullscreen()) || (!toggled && cfg.hideScrollbars()) ) { d->currentImageView->canvasController()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); d->currentImageView->canvasController()->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); } else { d->currentImageView->canvasController()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); d->currentImageView->canvasController()->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); } } void KisViewManager::slotSaveShowRulersState(bool value) { KisConfig cfg(false); cfg.setShowRulers(value); } void KisViewManager::slotSaveRulersTrackMouseState(bool value) { KisConfig cfg(false); cfg.setRulersTrackMouse(value); } void KisViewManager::setShowFloatingMessage(bool show) { d->showFloatingMessage = show; } void KisViewManager::changeAuthorProfile(const QString &profileName) { KConfigGroup appAuthorGroup(KSharedConfig::openConfig(), "Author"); if (profileName.isEmpty() || profileName == i18nc("choice for author profile", "Anonymous")) { appAuthorGroup.writeEntry("active-profile", ""); } else { appAuthorGroup.writeEntry("active-profile", profileName); } appAuthorGroup.sync(); Q_FOREACH (KisDocument *doc, KisPart::instance()->documents()) { doc->documentInfo()->updateParameters(); } } void KisViewManager::slotUpdateAuthorProfileActions() { Q_ASSERT(d->actionAuthor); if (!d->actionAuthor) { return; } d->actionAuthor->clear(); d->actionAuthor->addAction(i18nc("choice for author profile", "Anonymous")); KConfigGroup authorGroup(KSharedConfig::openConfig(), "Author"); QStringList profiles = authorGroup.readEntry("profile-names", QStringList()); QString authorInfo = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/authorinfo/"; QStringList filters = QStringList() << "*.authorinfo"; QDir dir(authorInfo); Q_FOREACH(QString entry, dir.entryList(filters)) { int ln = QString(".authorinfo").size(); entry.chop(ln); if (!profiles.contains(entry)) { profiles.append(entry); } } Q_FOREACH (const QString &profile , profiles) { d->actionAuthor->addAction(profile); } KConfigGroup appAuthorGroup(KSharedConfig::openConfig(), "Author"); QString profileName = appAuthorGroup.readEntry("active-profile", ""); if (profileName == "anonymous" || profileName.isEmpty()) { d->actionAuthor->setCurrentItem(0); } else if (profiles.contains(profileName)) { d->actionAuthor->setCurrentAction(profileName); } } void KisViewManager::slotUpdatePixelGridAction() { KIS_SAFE_ASSERT_RECOVER_RETURN(d->showPixelGrid); KisSignalsBlocker b(d->showPixelGrid); KisConfig cfg(true); d->showPixelGrid->setChecked(cfg.pixelGridEnabled() && cfg.useOpenGL()); } void KisViewManager::slotActivateTransformTool() { if(KoToolManager::instance()->activeToolId() == "KisToolTransform") { KoToolBase* tool = KoToolManager::instance()->toolById(canvasBase(), "KisToolTransform"); QSet dummy; // Start a new stroke tool->deactivate(); tool->activate(KoToolBase::DefaultActivation, dummy); } KoToolManager::instance()->switchToolRequested("KisToolTransform"); } void KisViewManager::slotToggleFgBg() { KoColor newFg = d->canvasResourceManager.backgroundColor(); KoColor newBg = d->canvasResourceManager.foregroundColor(); /** * NOTE: Some of color selectors do not differentiate foreground * and background colors, so if one wants them to end up * being set up to foreground color, it should be set the * last. */ d->canvasResourceManager.setBackgroundColor(newBg); d->canvasResourceManager.setForegroundColor(newFg); } void KisViewManager::slotResetFgBg() { // see a comment in slotToggleFgBg() d->canvasResourceManager.setBackgroundColor(KoColor(Qt::white, KoColorSpaceRegistry::instance()->rgb8())); d->canvasResourceManager.setForegroundColor(KoColor(Qt::black, KoColorSpaceRegistry::instance()->rgb8())); } diff --git a/libs/ui/KisViewManager.h b/libs/ui/KisViewManager.h index 030aeac59e..3fc1ca2a54 100644 --- a/libs/ui/KisViewManager.h +++ b/libs/ui/KisViewManager.h @@ -1,261 +1,261 @@ /* * Copyright (c) 2006 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_GUI_CLIENT_H #define KIS_GUI_CLIENT_H #include #include #include #include #include #include #include #include "kis_floating_message.h" class QPoint; class KisView; class KisCanvas2; class KisCanvasResourceProvider; class KisDocument; class KisFilterManager; class KisGridManager; class KisGuidesManager; class KisImageManager; class KisNodeManager; class KisDecorationsManager; class KisPaintopBox; class KisSelectionManager; class KisStatusBar; class KisUndoAdapter; class KisZoomManager; class KisPaintopBox; class KisActionManager; class KisInputManager; class KoUpdater; class KoProgressUpdater; /** * KisViewManager manages the collection of views shown in a single mainwindow. */ class KRITAUI_EXPORT KisViewManager : public QObject { Q_OBJECT public: /** * Construct a new view on the krita document. - * @param document the document we show. * @param parent a parent widget we show ourselves in. + * @param actionCollection an action collection. */ KisViewManager(QWidget *parent, KActionCollection *actionCollection); ~KisViewManager() override; /** * Retrieves the entire action collection. */ virtual KActionCollection* actionCollection() const; public: // Krita specific interfaces void setCurrentView(KisView *view); /// Return the image this view is displaying KisImageWSP image() const; KoZoomController *zoomController() const; /// The resource provider contains all per-view settings, such as /// current color, current paint op etc. KisCanvasResourceProvider *resourceProvider(); /// Return the canvasbase class KisCanvas2 *canvasBase() const; /// Return the actual widget that is displaying the current image QWidget* canvas() const; /// Return the wrapper class around the statusbar KisStatusBar *statusBar() const; KisPaintopBox* paintOpBox() const; /// create a new progress updater QPointer createUnthreadedUpdater(const QString &name); QPointer createThreadedUpdater(const QString &name); /// The selection manager handles everything action related to /// selections. KisSelectionManager *selectionManager(); /// The node manager handles everything about nodes KisNodeManager *nodeManager() const; KisActionManager *actionManager() const; /** * Convenience method to get at the active node, which may be * a layer or a mask or a selection */ KisNodeSP activeNode(); /// Convenience method to get at the active layer KisLayerSP activeLayer(); /// Convenience method to get at the active paint device KisPaintDeviceSP activeDevice(); /// The filtermanager handles everything action-related to filters KisFilterManager *filterManager(); /// The image manager handles everything action-related to the /// current image KisImageManager *imageManager(); /// Filters events and sends them to canvas actions KisInputManager *inputManager() const; /// Convenience method to get at the active selection (the /// selection of the current layer, or, if that does not exist, /// the global selection. KisSelectionSP selection(); /// Checks if the current global or local selection is editable bool selectionEditable(); /// The undo adapter is used to add commands to the undo stack KisUndoAdapter *undoAdapter(); KisDocument *document() const; int viewCount() const; /** * @brief blockUntilOperationsFinished blocks the GUI of the application until execution * of actions on \p image is finished * @param image the image which we should wait for * @return true if the image has finished execution of the actions, false if * the user cancelled operation */ bool blockUntilOperationsFinished(KisImageSP image); /** * @brief blockUntilOperationsFinished blocks the GUI of the application until execution * of actions on \p image is finished. Does *not* provide a "Cancel" button. So the * user is forced to wait. * @param image the image which we should wait for */ void blockUntilOperationsFinishedForced(KisImageSP image); public: KisGridManager * gridManager() const; KisGuidesManager * guidesManager() const; /// disable and enable toolbar controls. used for disabling them during painting. void enableControls(); void disableControls(); /// shows a floating message in the top right corner of the canvas void showFloatingMessage(const QString &message, const QIcon& icon, int timeout = 4500, KisFloatingMessage::Priority priority = KisFloatingMessage::Medium, int alignment = Qt::AlignCenter | Qt::TextWordWrap); /// @return the KoMaindow this view is in, or 0 KisMainWindow *mainWindow() const; /// The QMainWindow associated with this view. This is most likely going to be shell(), but /// when running as Gemini or Sketch, this will be set to the applications' own QMainWindow. /// This can be checked by qobject_casting to KisMainWindow to check the difference. QMainWindow* qtMainWindow() const; /// The mainWindow function will return the shell() value, unless this function is called /// with a non-null value. To make it return shell() again, simply pass null to this function. void setQtMainWindow(QMainWindow* newMainWindow); static void initializeResourceManager(KoCanvasResourceProvider *resourceManager); public Q_SLOTS: void switchCanvasOnly(bool toggled); void setShowFloatingMessage(bool show); void showHideScrollbars(); /// Visit all managers to update gui elements, e.g. enable / disable actions. /// This is heavy-duty call, so it uses a compressor. void updateGUI(); /// Update the style of all the icons void updateIcons(); void slotViewAdded(KisView *view); void slotViewRemoved(KisView *view); void slotActivateTransformTool(); // Change and update author void changeAuthorProfile(const QString &profileName); void slotUpdateAuthorProfileActions(); Q_SIGNALS: void floatingMessageRequested(const QString &message, const QString &iconName); /** * @brief viewChanged * sent out when the view has changed. */ void viewChanged(); private Q_SLOTS: void slotBlacklistCleanup(); void slotCreateTemplate(); void slotCreateCopy(); void slotDocumentSaved(); void slotSaveIncremental(); void slotSaveIncrementalBackup(); void showStatusBar(bool toggled); void toggleTabletLogger(); void openResourcesDirectory(); void initializeStatusBarVisibility(); void guiUpdateTimeout(); void slotUpdatePixelGridAction(); void slotSaveShowRulersState(bool value); void slotSaveRulersTrackMouseState(bool value); void slotToggleFgBg(); void slotResetFgBg(); private: void createActions(); void setupManagers(); /// The zoommanager handles everything action-related to zooming KisZoomManager * zoomManager(); private: class KisViewManagerPrivate; KisViewManagerPrivate * const d; }; #endif diff --git a/libs/ui/canvas/kis_animation_player.cpp b/libs/ui/canvas/kis_animation_player.cpp index 1531d6470c..c213d2f0e4 100644 --- a/libs/ui/canvas/kis_animation_player.cpp +++ b/libs/ui/canvas/kis_animation_player.cpp @@ -1,622 +1,622 @@ /* * Copyright (c) 2015 Jouni Pentikäinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 "kis_animation_player.h" #include #include #include //#define PLAYER_DEBUG_FRAMERATE #include "kis_global.h" #include "kis_algebra_2d.h" #include "kis_config.h" #include "kis_config_notifier.h" #include "kis_image.h" #include "kis_canvas2.h" #include "kis_animation_frame_cache.h" #include "kis_signal_auto_connection.h" #include "kis_image_animation_interface.h" #include "kis_time_range.h" #include "kis_signal_compressor.h" #include #include #include "KisSyncedAudioPlayback.h" #include "kis_signal_compressor_with_param.h" #include "kis_image_config.h" #include #include "KisViewManager.h" #include "kis_icon_utils.h" #include "KisPart.h" #include "dialogs/KisAsyncAnimationCacheRenderDialog.h" #include "KisRollingMeanAccumulatorWrapper.h" struct KisAnimationPlayer::Private { public: Private(KisAnimationPlayer *_q) : q(_q), realFpsAccumulator(24), droppedFpsAccumulator(24), droppedFramesPortion(24), dropFramesMode(true), nextFrameExpectedTime(0), expectedInterval(0), currentFrame(0), lastTimerInterval(0), lastPaintedFrame(0), playbackStatisticsCompressor(1000, KisSignalCompressor::FIRST_INACTIVE), stopAudioOnScrubbingCompressor(100, KisSignalCompressor::POSTPONE), audioOffsetTolerance(-1) {} KisAnimationPlayer *q; bool useFastFrameUpload; bool playing; QTimer *timer; /// The frame user started playback from int uiFrame; int firstFrame; int lastFrame; qreal playbackSpeed; KisCanvas2 *canvas; KisSignalAutoConnectionsStore cancelStrokeConnections; QElapsedTimer realFpsTimer; KisRollingMeanAccumulatorWrapper realFpsAccumulator; KisRollingMeanAccumulatorWrapper droppedFpsAccumulator; KisRollingMeanAccumulatorWrapper droppedFramesPortion; bool dropFramesMode; /// Measures time since playback (re)started QElapsedTimer playbackTime; int nextFrameExpectedTime; int expectedInterval; /// The frame the current playback (re)started on int initialFrame; /// The frame currently displayed int currentFrame; int lastTimerInterval; int lastPaintedFrame; KisSignalCompressor playbackStatisticsCompressor; QScopedPointer syncedAudio; QScopedPointer > audioSyncScrubbingCompressor; KisSignalCompressor stopAudioOnScrubbingCompressor; int audioOffsetTolerance; void stopImpl(bool doUpdates); int incFrame(int frame, int inc) { frame += inc; if (frame > lastFrame) { const int framesFromFirst = frame - firstFrame; const int rangeLength = lastFrame - firstFrame + 1; frame = firstFrame + framesFromFirst % rangeLength; } return frame; } qint64 framesToMSec(qreal value, int fps) const { return qRound(value / fps * 1000.0); } qreal msecToFrames(qint64 value, int fps) const { return qreal(value) * fps / 1000.0; } int framesToWalltime(qreal frame, int fps) const { return qRound(framesToMSec(frame, fps) / playbackSpeed); } qreal walltimeToFrames(qint64 time, int fps) const { return msecToFrames(time, fps) * playbackSpeed; } qreal playbackTimeInFrames(int fps) const { const qint64 cycleLength = lastFrame - firstFrame + 1; const qreal framesPlayed = walltimeToFrames(playbackTime.elapsed(), fps); const qreal framesSinceFirst = std::fmod(initialFrame + framesPlayed - firstFrame, cycleLength); return firstFrame + framesSinceFirst; } }; KisAnimationPlayer::KisAnimationPlayer(KisCanvas2 *canvas) : QObject(canvas) , m_d(new Private(this)) { m_d->useFastFrameUpload = false; m_d->playing = false; m_d->canvas = canvas; m_d->playbackSpeed = 1.0; m_d->timer = new QTimer(this); connect(m_d->timer, SIGNAL(timeout()), this, SLOT(slotUpdate())); m_d->timer->setSingleShot(true); connect(KisConfigNotifier::instance(), SIGNAL(dropFramesModeChanged()), SLOT(slotUpdateDropFramesMode())); slotUpdateDropFramesMode(); connect(&m_d->playbackStatisticsCompressor, SIGNAL(timeout()), this, SIGNAL(sigPlaybackStatisticsUpdated())); using namespace std::placeholders; std::function callback( std::bind(&KisAnimationPlayer::slotSyncScrubbingAudio, this, _1)); const int defaultScrubbingUdpatesDelay = 40; /* 40 ms == 25 fps */ m_d->audioSyncScrubbingCompressor.reset( new KisSignalCompressorWithParam(defaultScrubbingUdpatesDelay, callback, KisSignalCompressor::FIRST_ACTIVE)); m_d->stopAudioOnScrubbingCompressor.setDelay(defaultScrubbingUdpatesDelay); connect(&m_d->stopAudioOnScrubbingCompressor, SIGNAL(timeout()), SLOT(slotTryStopScrubbingAudio())); connect(m_d->canvas->image()->animationInterface(), SIGNAL(sigFramerateChanged()), SLOT(slotUpdateAudioChunkLength())); slotUpdateAudioChunkLength(); connect(m_d->canvas->image()->animationInterface(), SIGNAL(sigAudioChannelChanged()), SLOT(slotAudioChannelChanged())); connect(m_d->canvas->image()->animationInterface(), SIGNAL(sigAudioVolumeChanged()), SLOT(slotAudioVolumeChanged())); slotAudioChannelChanged(); } KisAnimationPlayer::~KisAnimationPlayer() {} void KisAnimationPlayer::slotUpdateDropFramesMode() { KisConfig cfg(true); m_d->dropFramesMode = cfg.animationDropFrames(); } void KisAnimationPlayer::slotSyncScrubbingAudio(int msecTime) { KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->syncedAudio); if (!m_d->syncedAudio->isPlaying()) { m_d->syncedAudio->play(msecTime); } else { m_d->syncedAudio->syncWithVideo(msecTime); } if (!isPlaying()) { m_d->stopAudioOnScrubbingCompressor.start(); } } void KisAnimationPlayer::slotTryStopScrubbingAudio() { KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->syncedAudio); if (m_d->syncedAudio && !isPlaying()) { m_d->syncedAudio->stop(); } } void KisAnimationPlayer::slotAudioChannelChanged() { KisImageAnimationInterface *interface = m_d->canvas->image()->animationInterface(); QString fileName = interface->audioChannelFileName(); QFileInfo info(fileName); if (info.exists() && !interface->isAudioMuted()) { m_d->syncedAudio.reset(new KisSyncedAudioPlayback(info.absoluteFilePath())); m_d->syncedAudio->setVolume(interface->audioVolume()); m_d->syncedAudio->setSoundOffsetTolerance(m_d->audioOffsetTolerance); connect(m_d->syncedAudio.data(), SIGNAL(error(QString,QString)), SLOT(slotOnAudioError(QString,QString))); } else { m_d->syncedAudio.reset(); } } void KisAnimationPlayer::slotAudioVolumeChanged() { KisImageAnimationInterface *interface = m_d->canvas->image()->animationInterface(); if (m_d->syncedAudio) { m_d->syncedAudio->setVolume(interface->audioVolume()); } } void KisAnimationPlayer::slotOnAudioError(const QString &fileName, const QString &message) { QString errorMessage(i18nc("floating on-canvas message", "Cannot open audio: \"%1\"\nError: %2", fileName, message)); m_d->canvas->viewManager()->showFloatingMessage(errorMessage, KisIconUtils::loadIcon("warning")); } void KisAnimationPlayer::connectCancelSignals() { m_d->cancelStrokeConnections.addConnection( m_d->canvas->image().data(), SIGNAL(sigUndoDuringStrokeRequested()), this, SLOT(slotCancelPlayback())); m_d->cancelStrokeConnections.addConnection( m_d->canvas->image().data(), SIGNAL(sigStrokeCancellationRequested()), this, SLOT(slotCancelPlayback())); m_d->cancelStrokeConnections.addConnection( m_d->canvas->image().data(), SIGNAL(sigStrokeEndRequested()), this, SLOT(slotCancelPlaybackSafe())); m_d->cancelStrokeConnections.addConnection( m_d->canvas->image()->animationInterface(), SIGNAL(sigFramerateChanged()), this, SLOT(slotUpdatePlaybackTimer())); m_d->cancelStrokeConnections.addConnection( m_d->canvas->image()->animationInterface(), SIGNAL(sigFullClipRangeChanged()), this, SLOT(slotUpdatePlaybackTimer())); m_d->cancelStrokeConnections.addConnection( m_d->canvas->image()->animationInterface(), SIGNAL(sigPlaybackRangeChanged()), this, SLOT(slotUpdatePlaybackTimer())); } void KisAnimationPlayer::disconnectCancelSignals() { m_d->cancelStrokeConnections.clear(); } void KisAnimationPlayer::slotUpdateAudioChunkLength() { const KisImageAnimationInterface *animation = m_d->canvas->image()->animationInterface(); const int animationFramePeriod = qMax(1, 1000 / animation->framerate()); KisConfig cfg(true); int scrubbingAudioUdpatesDelay = cfg.scrubbingAudioUpdatesDelay(); if (scrubbingAudioUdpatesDelay < 0) { scrubbingAudioUdpatesDelay = qMax(1, animationFramePeriod); } m_d->audioSyncScrubbingCompressor->setDelay(scrubbingAudioUdpatesDelay); m_d->stopAudioOnScrubbingCompressor.setDelay(scrubbingAudioUdpatesDelay); m_d->audioOffsetTolerance = cfg.audioOffsetTolerance(); if (m_d->audioOffsetTolerance < 0) { m_d->audioOffsetTolerance = animationFramePeriod; } if (m_d->syncedAudio) { m_d->syncedAudio->setSoundOffsetTolerance(m_d->audioOffsetTolerance); } if (m_d->playing) { slotUpdatePlaybackTimer(); } } void KisAnimationPlayer::slotUpdatePlaybackTimer() { m_d->timer->stop(); const KisImageAnimationInterface *animation = m_d->canvas->image()->animationInterface(); const KisTimeRange &playBackRange = animation->playbackRange(); if (!playBackRange.isValid()) return; const int fps = animation->framerate(); m_d->initialFrame = isPlaying() ? m_d->currentFrame : animation->currentUITime(); m_d->firstFrame = playBackRange.start(); m_d->lastFrame = playBackRange.end(); m_d->currentFrame = qBound(m_d->firstFrame, m_d->currentFrame, m_d->lastFrame); m_d->expectedInterval = m_d->framesToWalltime(1, fps); m_d->lastTimerInterval = m_d->expectedInterval; if (m_d->syncedAudio) { m_d->syncedAudio->setSpeed(m_d->playbackSpeed); const qint64 expectedAudioTime = m_d->framesToMSec(m_d->currentFrame, fps); if (qAbs(m_d->syncedAudio->position() - expectedAudioTime) > m_d->framesToMSec(1.5, fps)) { m_d->syncedAudio->syncWithVideo(expectedAudioTime); } } m_d->timer->start(m_d->expectedInterval); if (m_d->playbackTime.isValid()) { m_d->playbackTime.restart(); } else { m_d->playbackTime.start(); } m_d->nextFrameExpectedTime = m_d->playbackTime.elapsed() + m_d->expectedInterval; } void KisAnimationPlayer::play() { const KisImageAnimationInterface *animation = m_d->canvas->image()->animationInterface(); { const KisTimeRange &range = animation->playbackRange(); if (!range.isValid()) return; // when openGL is disabled, there is no animation cache if (m_d->canvas->frameCache()) { KisImageConfig cfg(true); const int dimensionLimit = cfg.useAnimationCacheFrameSizeLimit() ? cfg.animationCacheFrameSizeLimit() : std::numeric_limits::max(); const int maxImageDimension = KisAlgebra2D::maxDimension(m_d->canvas->image()->bounds()); const QRect regionOfInterest = cfg.useAnimationCacheRegionOfInterest() && maxImageDimension > dimensionLimit ? m_d->canvas->regionOfInterest() : m_d->canvas->coordinatesConverter()->imageRectInImagePixels(); const QRect minimalNeedRect = m_d->canvas->coordinatesConverter()->widgetRectInImagePixels().toAlignedRect() & m_d->canvas->coordinatesConverter()->imageRectInImagePixels(); m_d->canvas->frameCache()->dropLowQualityFrames(range, regionOfInterest, minimalNeedRect); KisAsyncAnimationCacheRenderDialog dlg(m_d->canvas->frameCache(), range, 200); dlg.setRegionOfInterest(regionOfInterest); KisAsyncAnimationCacheRenderDialog::Result result = dlg.regenerateRange(m_d->canvas->viewManager()); if (result != KisAsyncAnimationCacheRenderDialog::RenderComplete) { return; } m_d->canvas->setRenderingLimit(regionOfInterest); } } m_d->playing = true; m_d->uiFrame = animation->currentUITime(); m_d->currentFrame = m_d->uiFrame; slotUpdatePlaybackTimer(); m_d->lastPaintedFrame = -1; connectCancelSignals(); if (m_d->syncedAudio) { KisImageAnimationInterface *animationInterface = m_d->canvas->image()->animationInterface(); m_d->syncedAudio->play(m_d->framesToMSec(m_d->currentFrame, animationInterface->framerate())); } emit sigPlaybackStarted(); } void KisAnimationPlayer::Private::stopImpl(bool doUpdates) { if (syncedAudio) { syncedAudio->stop(); } q->disconnectCancelSignals(); timer->stop(); playing = false; canvas->setRenderingLimit(QRect()); if (doUpdates) { KisImageAnimationInterface *animation = canvas->image()->animationInterface(); if (animation->currentUITime() == uiFrame) { canvas->refetchDataFromImage(); } else { animation->switchCurrentTimeAsync(uiFrame); } } emit q->sigPlaybackStopped(); } void KisAnimationPlayer::stop() { m_d->stopImpl(true); } void KisAnimationPlayer::forcedStopOnExit() { m_d->stopImpl(false); } bool KisAnimationPlayer::isPlaying() { return m_d->playing; } int KisAnimationPlayer::currentTime() { return m_d->lastPaintedFrame; } void KisAnimationPlayer::displayFrame(int time) { uploadFrame(time, true); } void KisAnimationPlayer::slotUpdate() { uploadFrame(-1, false); } void KisAnimationPlayer::uploadFrame(int frame, bool forceSyncAudio) { KisImageAnimationInterface *animationInterface = m_d->canvas->image()->animationInterface(); const int fps = animationInterface->framerate(); const bool syncToAudio = !forceSyncAudio && m_d->dropFramesMode && m_d->syncedAudio && m_d->syncedAudio->isPlaying(); if (frame < 0) { if (m_d->dropFramesMode) { const qreal currentTimeInFrames = syncToAudio ? m_d->msecToFrames(m_d->syncedAudio->position(), fps) : m_d->playbackTimeInFrames(fps); frame = qFloor(currentTimeInFrames); const int timeToNextFrame = m_d->framesToWalltime(frame + 1 - currentTimeInFrames, fps); m_d->lastTimerInterval = qMax(0, timeToNextFrame); if (frame < m_d->currentFrame) { // Returned to beginning of animation. Restart audio playback. forceSyncAudio = true; } } else { const qint64 currentTime = m_d->playbackTime.elapsed(); const qint64 framesDiff = currentTime - m_d->nextFrameExpectedTime; frame = m_d->incFrame(m_d->currentFrame, 1); m_d->nextFrameExpectedTime = currentTime + m_d->expectedInterval; m_d->lastTimerInterval = qMax(0.0, m_d->lastTimerInterval - 0.5 * framesDiff); } m_d->currentFrame = frame; m_d->timer->start(m_d->lastTimerInterval); m_d->playbackStatisticsCompressor.start(); } if (m_d->syncedAudio && (!syncToAudio || forceSyncAudio)) { const int msecTime = m_d->framesToMSec(frame, fps); if (isPlaying()) { slotSyncScrubbingAudio(msecTime); } else { m_d->audioSyncScrubbingCompressor->start(msecTime); } } bool useFallbackUploadMethod = !m_d->canvas->frameCache(); if (m_d->canvas->frameCache() && m_d->canvas->frameCache()->shouldUploadNewFrame(frame, m_d->lastPaintedFrame)) { if (m_d->canvas->frameCache()->uploadFrame(frame)) { m_d->canvas->updateCanvas(); m_d->useFastFrameUpload = true; } else { useFallbackUploadMethod = true; } } if (useFallbackUploadMethod) { + // no OpenGL cache or the frame just not cached yet m_d->useFastFrameUpload = false; m_d->canvas->image()->barrierLock(true); m_d->canvas->image()->unlock(); - - // no OpenGL cache or the frame just not cached yet - animationInterface->switchCurrentTimeAsync(frame); } + animationInterface->switchCurrentTimeAsync(frame); + if (!m_d->realFpsTimer.isValid()) { m_d->realFpsTimer.start(); } else { const int elapsed = m_d->realFpsTimer.restart(); m_d->realFpsAccumulator(elapsed); if (m_d->lastPaintedFrame >= 0) { int numFrames = frame - m_d->lastPaintedFrame; if (numFrames < 0) { numFrames += m_d->lastFrame - m_d->firstFrame + 1; } m_d->droppedFramesPortion(qreal(int(numFrames != 1))); if (numFrames > 0) { m_d->droppedFpsAccumulator(qreal(elapsed) / numFrames); } #ifdef PLAYER_DEBUG_FRAMERATE qDebug() << " RFPS:" << 1000.0 / m_d->realFpsAccumulator.rollingMean() << "DFPS:" << 1000.0 / m_d->droppedFpsAccumulator.rollingMean() << ppVar(numFrames); #endif /* PLAYER_DEBUG_FRAMERATE */ } } m_d->lastPaintedFrame = frame; emit sigFrameChanged(); } qreal KisAnimationPlayer::effectiveFps() const { return 1000.0 / m_d->droppedFpsAccumulator.rollingMean(); } qreal KisAnimationPlayer::realFps() const { return 1000.0 / m_d->realFpsAccumulator.rollingMean(); } qreal KisAnimationPlayer::framesDroppedPortion() const { return m_d->droppedFramesPortion.rollingMean(); } void KisAnimationPlayer::slotCancelPlayback() { stop(); } void KisAnimationPlayer::slotCancelPlaybackSafe() { /** * If there is no openGL support, then we have no (!) cache at * all. Therefore we should regenerate frame on every time switch, * which, yeah, can be very slow. What is more important, when * regenerating a frame animation interface will emit a * sigStrokeEndRequested() signal and we should ignore it. That is * not an ideal solution, because the user will be able to paint * on random frames while playing, but it lets users with faulty * GPUs see at least some preview of their animation. */ if (m_d->useFastFrameUpload) { stop(); } } qreal KisAnimationPlayer::playbackSpeed() { return m_d->playbackSpeed; } void KisAnimationPlayer::slotUpdatePlaybackSpeed(double value) { m_d->playbackSpeed = value; if (m_d->playing) { slotUpdatePlaybackTimer(); } } diff --git a/libs/ui/canvas/kis_canvas_decoration.h b/libs/ui/canvas/kis_canvas_decoration.h index da49f69285..59094ebb08 100644 --- a/libs/ui/canvas/kis_canvas_decoration.h +++ b/libs/ui/canvas/kis_canvas_decoration.h @@ -1,105 +1,108 @@ /* * Copyright (c) 2008 Cyrille Berger * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 _KIS_CANVAS_DECORATION_H_ #define _KIS_CANVAS_DECORATION_H_ #include #include #include #include #include "KisView.h" #include class KisCanvas2; class QRectF; class QPainter; class KisCoordinatesConverter; class KisCanvasDecoration; typedef KisSharedPtr KisCanvasDecorationSP; /** * This class is the base class for object that draw a decoration on the canvas, * for instance, selections, grids, tools, ... */ class KRITAUI_EXPORT KisCanvasDecoration : public QObject, public KisShared { Q_OBJECT public: KisCanvasDecoration(const QString& id, QPointerparent); ~KisCanvasDecoration() override; void setView(QPointer imageView); const QString& id() const; /** * @return whether the decoration is visible. */ bool visible() const; /** - * Will paint the decoration on the QPainter, if the visible is set to true. + * Will paint the decoration on the QPainter, if the visible is set to @c true. * + * @param gc the painter * @param updateRect dirty rect in document pixels + * @param converter coordinate converter + * @param canvas the canvas */ void paint(QPainter& gc, const QRectF& updateRect, const KisCoordinatesConverter *converter,KisCanvas2* canvas); /** * Return z-order priority of the decoration. The higher the priority, the higher * the decoration is painted. */ int priority() const; static bool comparePriority(KisCanvasDecorationSP decoration1, KisCanvasDecorationSP decoration2); public Q_SLOTS: /** * Set if the decoration is visible or not. */ virtual void setVisible(bool v); /** * If decoration is visible, hide it, if not show it. */ void toggleVisibility(); protected: virtual void drawDecoration(QPainter& gc, const QRectF& updateArea, const KisCoordinatesConverter *converter,KisCanvas2* canvas) = 0; /// XXX: unify view and imageview! QPointerimageView(); /** * @return the parent KisView */ QPointer view() const; /** * Set the priority of the decoration. The higher the priority, the higher * the decoration is painted. */ void setPriority(int value); private: struct Private; Private* const d; }; #endif diff --git a/libs/ui/canvas/kis_image_patch.h b/libs/ui/canvas/kis_image_patch.h index fe826ab288..5ddcbc6f3a 100644 --- a/libs/ui/canvas/kis_image_patch.h +++ b/libs/ui/canvas/kis_image_patch.h @@ -1,111 +1,111 @@ /* * Copyright (c) 2010 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_IMAGE_PATCH_H_ #define KIS_IMAGE_PATCH_H_ #include #include #include #define BORDER_SIZE(scale) (ceil(0.5/scale)) class KisImagePatch { public: /** * A default constructor initializing invalid patch */ KisImagePatch(); /** * Initializes a new patch with given values. * Be careful, because the constructor does not fill * QImage of the patch, as the patch rect is not known yet * * \see setImage */ KisImagePatch(QRect imageRect, qint32 borderWidth, qreal scaleX, qreal scaleY); /** * Sets the image of the patch * Should be called right after the constructor * to finish initializing the object */ void setImage(QImage image); /** * prescale the patch image. Call after setImage(). * This ensures that we use the QImage smoothscale method, not the QPainter scaling, * which is far inferior. */ void preScale(const QRectF &dstRect); /** * Returns the rect of KisImage covered by the image * of the patch (in KisImage pixels) * * \see m_patchRect */ QRect patchRect(); /** - * Draws an m_interestRect of the patch onto @gc - * By the way it fits this rect into @dstRect - * @renderHints are directly transmitted to QPainter + * Draws an m_interestRect of the patch onto @p gc + * By the way it fits this rect into @p dstRect + * @p renderHints are directly transmitted to QPainter */ void drawMe(QPainter &gc, const QRectF &dstRect, QPainter::RenderHints renderHints); /** * Checks whether the patch can be used for drawing the image */ bool isValid(); private: /** * The scale of the image stored in the patch */ qreal m_scaleX; qreal m_scaleY; /** * The rect of KisImage covered by the image * of the patch (in KisImage pixels) */ QRect m_patchRect; /** * The rect that was requested during creation * of the patch. It equals to patchRect withount * borders * These borders are introdused for more accurate * smooth scaling to reduce border effects * (IN m_image PIXELS, relative to m_image's topLeft); */ QRectF m_interestRect; QImage m_image; bool m_isScaled; }; #endif /* KIS_IMAGE_PATCH_H_ */ diff --git a/libs/ui/canvas/kis_image_pyramid.cpp b/libs/ui/canvas/kis_image_pyramid.cpp index 04b74c0ef3..75d2a4f786 100644 --- a/libs/ui/canvas/kis_image_pyramid.cpp +++ b/libs/ui/canvas/kis_image_pyramid.cpp @@ -1,537 +1,537 @@ /* * Copyright (c) 2009 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 "kis_image_pyramid.h" #include #include #include #include #include #include #include "kis_display_filter.h" #include "kis_painter.h" #include "kis_iterator_ng.h" #include "kis_datamanager.h" #include "kis_config_notifier.h" #include "kis_debug.h" #include "kis_config.h" #include "kis_image_config.h" //#define DEBUG_PYRAMID #include #ifdef HAVE_OCIO #include #include #endif #define ORIGINAL_INDEX 0 #define FIRST_NOT_ORIGINAL_INDEX 1 #define SCALE_FROM_INDEX(idx) (1./qreal(1<<(idx))) /************* AUXILIARY FUNCTIONS **********************************/ #include #ifdef HAVE_OPENEXR #include #endif #define ceiledSize(sz) QSize(ceil((sz).width()), ceil((sz).height())) #define isOdd(x) ((x) & 0x01) /** - * Aligns @value to the lowest integer not smaller than @value and + * Aligns @p value to the lowest integer not smaller than @p value and * that is a divident of alignment */ inline void alignByPow2Hi(qint32 &value, qint32 alignment) { qint32 mask = alignment - 1; value |= mask; value++; } /** - * Aligns @value to the lowest integer not smaller than @value and + * Aligns @p value to the lowest integer not smaller than @p value and * that is, increased by one, a divident of alignment */ inline void alignByPow2ButOneHi(qint32 &value, qint32 alignment) { qint32 mask = alignment - 1; value |= mask; } /** - * Aligns @value to the highest integer not exceeding @value and - * that is a divident of @alignment + * Aligns @p value to the highest integer not exceeding @p value and + * that is a divident of @p alignment */ inline void alignByPow2Lo(qint32 &value, qint32 alignment) { qint32 mask = alignment - 1; value &= ~mask; } inline void alignRectBy2(qint32 &x, qint32 &y, qint32 &w, qint32 &h) { x -= isOdd(x); y -= isOdd(y); w += isOdd(x); w += isOdd(w); h += isOdd(y); h += isOdd(h); } /************* class KisImagePyramid ********************************/ KisImagePyramid::KisImagePyramid(qint32 pyramidHeight) : m_monitorProfile(0) , m_monitorColorSpace(0) , m_pyramidHeight(pyramidHeight) { configChanged(); connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), this, SLOT(configChanged())); } KisImagePyramid::~KisImagePyramid() { setImage(0); } void KisImagePyramid::setMonitorProfile(const KoColorProfile* monitorProfile, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) { m_monitorProfile = monitorProfile; /** * If you change pixel size here, don't forget to change it * in optimized function downsamplePixels() */ m_monitorColorSpace = KoColorSpaceRegistry::instance()->rgb8(monitorProfile); m_renderingIntent = renderingIntent; m_conversionFlags = conversionFlags; rebuildPyramid(); } void KisImagePyramid::setChannelFlags(const QBitArray &channelFlags) { m_channelFlags = channelFlags; int selectedChannels = 0; const KoColorSpace *projectionCs = m_originalImage->projection()->colorSpace(); QList channelInfo = projectionCs->channels(); if (channelInfo.size() != m_channelFlags.size()) { m_channelFlags = QBitArray(); } for (int i = 0; i < m_channelFlags.size(); ++i) { if (m_channelFlags.testBit(i) && channelInfo[i]->channelType() == KoChannelInfo::COLOR) { selectedChannels++; m_selectedChannelIndex = i; } } m_allChannelsSelected = (selectedChannels == m_channelFlags.size()); m_onlyOneChannelSelected = (selectedChannels == 1); } void KisImagePyramid::setDisplayFilter(QSharedPointer displayFilter) { m_displayFilter = displayFilter; } void KisImagePyramid::rebuildPyramid() { m_pyramid.clear(); for (qint32 i = 0; i < m_pyramidHeight; i++) { m_pyramid.append(new KisPaintDevice(m_monitorColorSpace)); } } void KisImagePyramid::clearPyramid() { for (qint32 i = 0; i < m_pyramidHeight; i++) { m_pyramid[i]->clear(); } } void KisImagePyramid::setImage(KisImageWSP newImage) { if (newImage) { m_originalImage = newImage; clearPyramid(); setImageSize(m_originalImage->width(), m_originalImage->height()); // Get the full image size QRect rc = m_originalImage->projection()->exactBounds(); KisImageConfig config(true); int patchWidth = config.updatePatchWidth(); int patchHeight = config.updatePatchHeight(); if (rc.width() * rc.height() <= patchWidth * patchHeight) { retrieveImageData(rc); } else { qint32 firstCol = rc.x() / patchWidth; qint32 firstRow = rc.y() / patchHeight; qint32 lastCol = (rc.x() + rc.width()) / patchWidth; qint32 lastRow = (rc.y() + rc.height()) / patchHeight; for(qint32 i = firstRow; i <= lastRow; i++) { for(qint32 j = firstCol; j <= lastCol; j++) { QRect maxPatchRect(j * patchWidth, i * patchHeight, patchWidth, patchHeight); QRect patchRect = rc & maxPatchRect; retrieveImageData(patchRect); } } } //TODO: check whether there is needed recalculateCache() } } void KisImagePyramid::setImageSize(qint32 w, qint32 h) { Q_UNUSED(w); Q_UNUSED(h); /* nothing interesting */ } void KisImagePyramid::updateCache(const QRect &dirtyImageRect) { retrieveImageData(dirtyImageRect); } void KisImagePyramid::retrieveImageData(const QRect &rect) { // XXX: use QThreadStorage to cache the two patches (512x512) of pixels. Note // that when we do that, we need to reset that cache when the projection's // colorspace changes. const KoColorSpace *projectionCs = m_originalImage->projection()->colorSpace(); KisPaintDeviceSP originalProjection = m_originalImage->projection(); quint32 numPixels = rect.width() * rect.height(); QScopedArrayPointer originalBytes( new quint8[originalProjection->colorSpace()->pixelSize() * numPixels]); originalProjection->readBytes(originalBytes.data(), rect); if (m_displayFilter && m_useOcio && projectionCs->colorModelId() == RGBAColorModelID) { #ifdef HAVE_OCIO const KoColorProfile *destinationProfile = m_displayFilter->useInternalColorManagement() ? m_monitorProfile : projectionCs->profile(); const KoColorSpace *floatCs = KoColorSpaceRegistry::instance()->colorSpace( RGBAColorModelID.id(), Float32BitsColorDepthID.id(), destinationProfile); const KoColorSpace *modifiedMonitorCs = KoColorSpaceRegistry::instance()->colorSpace( RGBAColorModelID.id(), Integer8BitsColorDepthID.id(), destinationProfile); if (projectionCs->colorDepthId() == Float32BitsColorDepthID) { m_displayFilter->filter(originalBytes.data(), numPixels); } else { QScopedArrayPointer dst(new quint8[floatCs->pixelSize() * numPixels]); projectionCs->convertPixelsTo(originalBytes.data(), dst.data(), floatCs, numPixels, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); m_displayFilter->filter(dst.data(), numPixels); originalBytes.swap(dst); } { QScopedArrayPointer dst(new quint8[modifiedMonitorCs->pixelSize() * numPixels]); floatCs->convertPixelsTo(originalBytes.data(), dst.data(), modifiedMonitorCs, numPixels, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); originalBytes.swap(dst); } #endif } else { QList channelInfo = projectionCs->channels(); if (m_channelFlags.size() != channelInfo.size()) { setChannelFlags(QBitArray()); } if (!m_channelFlags.isEmpty() && !m_allChannelsSelected) { QScopedArrayPointer dst(new quint8[projectionCs->pixelSize() * numPixels]); int channelSize = channelInfo[m_selectedChannelIndex]->size(); int pixelSize = projectionCs->pixelSize(); KisConfig cfg(true); if (m_onlyOneChannelSelected && !cfg.showSingleChannelAsColor()) { int selectedChannelPos = channelInfo[m_selectedChannelIndex]->pos(); for (uint pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) { for (uint channelIndex = 0; channelIndex < projectionCs->channelCount(); ++channelIndex) { if (channelInfo[channelIndex]->channelType() == KoChannelInfo::COLOR) { memcpy(dst.data() + (pixelIndex * pixelSize) + (channelIndex * channelSize), originalBytes.data() + (pixelIndex * pixelSize) + selectedChannelPos, channelSize); } else if (channelInfo[channelIndex]->channelType() == KoChannelInfo::ALPHA) { memcpy(dst.data() + (pixelIndex * pixelSize) + (channelIndex * channelSize), originalBytes.data() + (pixelIndex * pixelSize) + (channelIndex * channelSize), channelSize); } } } } else { for (uint pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) { for (uint channelIndex = 0; channelIndex < projectionCs->channelCount(); ++channelIndex) { if (m_channelFlags.testBit(channelIndex)) { memcpy(dst.data() + (pixelIndex * pixelSize) + (channelIndex * channelSize), originalBytes.data() + (pixelIndex * pixelSize) + (channelIndex * channelSize), channelSize); } else { memset(dst.data() + (pixelIndex * pixelSize) + (channelIndex * channelSize), 0, channelSize); } } } } originalBytes.swap(dst); } QScopedArrayPointer dst(new quint8[m_monitorColorSpace->pixelSize() * numPixels]); projectionCs->convertPixelsTo(originalBytes.data(), dst.data(), m_monitorColorSpace, numPixels, m_renderingIntent, m_conversionFlags); originalBytes.swap(dst); } m_pyramid[ORIGINAL_INDEX]->writeBytes(originalBytes.data(), rect); } void KisImagePyramid::recalculateCache(KisPPUpdateInfoSP info) { KisPaintDevice *src; KisPaintDevice *dst; QRect currentSrcRect = info->dirtyImageRectVar; for (int i = FIRST_NOT_ORIGINAL_INDEX; i < m_pyramidHeight; i++) { src = m_pyramid[i-1].data(); dst = m_pyramid[i].data(); if (!currentSrcRect.isEmpty()) { currentSrcRect = downsampleByFactor2(currentSrcRect, src, dst); } } #ifdef DEBUG_PYRAMID QImage image = m_pyramid[ORIGINAL_INDEX]->convertToQImage(m_monitorProfile, m_renderingIntent, m_conversionFlags); image.save("./PYRAMID_BASE.png"); image = m_pyramid[1]->convertToQImage(m_monitorProfile, m_renderingIntent, m_conversionFlags); image.save("./LEVEL1.png"); image = m_pyramid[2]->convertToQImage(m_monitorProfile, m_renderingIntent, m_conversionFlags); image.save("./LEVEL2.png"); image = m_pyramid[3]->convertToQImage(m_monitorProfile, m_renderingIntent, m_conversionFlags); image.save("./LEVEL3.png"); #endif } QRect KisImagePyramid::downsampleByFactor2(const QRect& srcRect, KisPaintDevice* src, KisPaintDevice* dst) { qint32 srcX, srcY, srcWidth, srcHeight; srcRect.getRect(&srcX, &srcY, &srcWidth, &srcHeight); alignRectBy2(srcX, srcY, srcWidth, srcHeight); // Nothing to do if (srcWidth < 1) return QRect(); if (srcHeight < 1) return QRect(); qint32 dstX = srcX / 2; qint32 dstY = srcY / 2; qint32 dstWidth = srcWidth / 2; qint32 dstHeight = srcHeight / 2; KisHLineConstIteratorSP srcIt0 = src->createHLineConstIteratorNG(srcX, srcY, srcWidth); KisHLineConstIteratorSP srcIt1 = src->createHLineConstIteratorNG(srcX, srcY + 1, srcWidth); KisHLineIteratorSP dstIt = dst->createHLineIteratorNG(dstX, dstY, dstWidth); int conseqPixels = 0; for (int row = 0; row < dstHeight; ++row) { do { int srcItConseq = srcIt0->nConseqPixels(); int dstItConseq = dstIt->nConseqPixels(); conseqPixels = qMin(srcItConseq, dstItConseq * 2); Q_ASSERT(!isOdd(conseqPixels)); downsamplePixels(srcIt0->oldRawData(), srcIt1->oldRawData(), dstIt->rawData(), conseqPixels); srcIt1->nextPixels(conseqPixels); dstIt->nextPixels(conseqPixels / 2); } while (srcIt0->nextPixels(conseqPixels)); srcIt0->nextRow(); srcIt0->nextRow(); srcIt1->nextRow(); srcIt1->nextRow(); dstIt->nextRow(); } return QRect(dstX, dstY, dstWidth, dstHeight); } void KisImagePyramid::downsamplePixels(const quint8 *srcRow0, const quint8 *srcRow1, quint8 *dstRow, qint32 numSrcPixels) { /** * FIXME (mandatory): Use SSE and friends here. */ qint16 b = 0; qint16 g = 0; qint16 r = 0; qint16 a = 0; static const qint32 pixelSize = 4; // This is preview argb8 mode for (qint32 i = 0; i < numSrcPixels / 2; i++) { b = srcRow0[0] + srcRow1[0] + srcRow0[4] + srcRow1[4]; g = srcRow0[1] + srcRow1[1] + srcRow0[5] + srcRow1[5]; r = srcRow0[2] + srcRow1[2] + srcRow0[6] + srcRow1[6]; a = srcRow0[3] + srcRow1[3] + srcRow0[7] + srcRow1[7]; dstRow[0] = b / 4; dstRow[1] = g / 4; dstRow[2] = r / 4; dstRow[3] = a / 4; dstRow += pixelSize; srcRow0 += 2 * pixelSize; srcRow1 += 2 * pixelSize; } } int KisImagePyramid::findFirstGoodPlaneIndex(qreal scale, QSize originalSize) { qint32 nearest = 0; for (qint32 i = 0; i < m_pyramidHeight; i++) { qreal planeScale = SCALE_FROM_INDEX(i); if (planeScale < scale) { if (originalSize*scale == originalSize*planeScale) nearest = i; break; } nearest = i; } // FOR DEBUGGING //nearest = 0; //nearest = qMin(1, nearest); dbgRender << "First good plane:" << nearest << "(sc:" << scale << ")"; return nearest; } void KisImagePyramid::alignSourceRect(QRect& rect, qreal scale) { qint32 index = findFirstGoodPlaneIndex(scale, rect.size()); qint32 alignment = 1 << index; dbgRender << "Before alignment:\t" << rect; /** * Assume that KisImage pixels are always positive * It allows us to use binary op-s for aligning */ Q_ASSERT(rect.left() >= 0 && rect.top() >= 0); qint32 x1, y1, x2, y2; rect.getCoords(&x1, &y1, &x2, &y2); alignByPow2Lo(x1, alignment); alignByPow2Lo(y1, alignment); /** * Here is a workaround of Qt's QRect::right()/bottom() * "historical reasons". It should be one pixel smaller * than actual right/bottom position */ alignByPow2ButOneHi(x2, alignment); alignByPow2ButOneHi(y2, alignment); rect.setCoords(x1, y1, x2, y2); dbgRender << "After alignment:\t" << rect; } KisImagePatch KisImagePyramid::getNearestPatch(KisPPUpdateInfoSP info) { qint32 index = findFirstGoodPlaneIndex(qMax(info->scaleX, info->scaleY), info->imageRect.size()); qreal planeScale = SCALE_FROM_INDEX(index); qint32 alignment = 1 << index; alignByPow2Hi(info->borderWidth, alignment); KisImagePatch patch(info->imageRect, info->borderWidth, planeScale, planeScale); patch.setImage(convertToQImageFast(m_pyramid[index], patch.patchRect())); return patch; } void KisImagePyramid::drawFromOriginalImage(QPainter& gc, KisPPUpdateInfoSP info) { KisImagePatch patch = getNearestPatch(info); patch.drawMe(gc, info->viewportRect, info->renderHints); } QImage KisImagePyramid::convertToQImageFast(KisPaintDeviceSP paintDevice, const QRect& unscaledRect) { qint32 x, y, w, h; unscaledRect.getRect(&x, &y, &w, &h); QImage image = QImage(w, h, QImage::Format_ARGB32); paintDevice->dataManager()->readBytes(image.bits(), x, y, w, h); return image; } void KisImagePyramid::configChanged() { KisConfig cfg(true); m_useOcio = cfg.useOcio(); } diff --git a/libs/ui/canvas/kis_projection_backend.h b/libs/ui/canvas/kis_projection_backend.h index 012062e0fb..fb3b7d4bfd 100644 --- a/libs/ui/canvas/kis_projection_backend.h +++ b/libs/ui/canvas/kis_projection_backend.h @@ -1,100 +1,100 @@ /* * Copyright (c) 2009 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_PROJECTION_BACKEND #define KIS_PROJECTION_BACKEND #include "kis_update_info.h" class KoColorProfile; class KisImagePatch; class KisDisplayFilter; #include /** * KisProjectionBackend is an abstract class representing * an object that can store a cache of KisImage projection. * More than that this object can perform some scaling operations * that are based on "patches" paradigm */ class KisProjectionBackend { public: virtual ~KisProjectionBackend(); /** * Those methods are related to KisPrescaledProjection's * equivalents */ virtual void setImage(KisImageWSP image) = 0; virtual void setImageSize(qint32 w, qint32 h) = 0; virtual void setMonitorProfile(const KoColorProfile* monitorProfile, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) = 0; virtual void setChannelFlags(const QBitArray &channelFlags) = 0; virtual void setDisplayFilter(QSharedPointer displayFilter) = 0; /** * Updates the cache of the backend by reading from * an associated image. All data transfers with * KisImage should happen here */ virtual void updateCache(const QRect &dirtyImageRect) = 0; /** * Prescales the cache of the backend. It is intended to be * called from a separate thread where you can easily * do the calculations. No data transfers with KisImage * should happen during this phase */ virtual void recalculateCache(KisPPUpdateInfoSP info) = 0; /** * Some backends cannot work with arbitrary areas due to * scaling stuff. That's why KisPrescaledProjection asks * a backend to align an image rect before any operations. */ virtual void alignSourceRect(QRect& rect, qreal scale); /** * Gets a patch from a backend that can draw a info.imageRect on some * QPainter in future. info.scaleX and info.scaleY are the scales * of planned drawing, btw, it doesn't mean that an QImage inside * the patch will have these scales - it'll have the nearest suitable * scale or even original scale (e.g. KisProjectionCache) * * If info.borderWidth is non-zero, info.requestedRect will * be expended by info.borderWidth pixels to all directions and * image of this rect will actually be written to the patch's QImage. * That is done to eliminate border effects in smooth scaling. */ virtual KisImagePatch getNearestPatch(KisPPUpdateInfoSP info) = 0; /** - * Draws a piece of original image onto @gc's canvas - * @param info.imageRect - area in KisImage pixels where to read from - * @param info.viewportRect - area in canvas pixels where to write to + * Draws a piece of original image onto @p gc 's canvas + * @p info.imageRect - area in KisImage pixels where to read from + * @p info.viewportRect - area in canvas pixels where to write to * If info.imageRect and info.viewportRect don't agree, the image * will be scaled - * @param info.borderWidth has the same meaning as in getNearestPatch - * @param info.renderHints - hints, transmitted to QPainter during darwing + * @p info.borderWidth has the same meaning as in getNearestPatch + * @p info.renderHints - hints, transmitted to QPainter during darwing */ virtual void drawFromOriginalImage(QPainter& gc, KisPPUpdateInfoSP info) = 0; }; #endif /* KIS_PROJECTION_BACKEND */ diff --git a/libs/ui/canvas/kis_update_info.h b/libs/ui/canvas/kis_update_info.h index 04e7493be6..01fcb90e40 100644 --- a/libs/ui/canvas/kis_update_info.h +++ b/libs/ui/canvas/kis_update_info.h @@ -1,168 +1,168 @@ /* * Copyright (c) 2010, Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_UPDATE_INFO_H_ #define KIS_UPDATE_INFO_H_ #include #include "kis_image_patch.h" #include "kis_shared.h" #include "kritaui_export.h" #include "opengl/kis_texture_tile_update_info.h" #include "kis_ui_types.h" class KRITAUI_EXPORT KisUpdateInfo : public KisShared { public: KisUpdateInfo(); virtual ~KisUpdateInfo(); virtual QRect dirtyViewportRect(); virtual QRect dirtyImageRect() const = 0; virtual int levelOfDetail() const = 0; }; Q_DECLARE_METATYPE(KisUpdateInfoSP) struct ConversionOptions { ConversionOptions() : m_needsConversion(false) {} ConversionOptions(const KoColorSpace *destinationColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) : m_needsConversion(true), m_destinationColorSpace(destinationColorSpace), m_renderingIntent(renderingIntent), m_conversionFlags(conversionFlags) { } bool m_needsConversion; const KoColorSpace *m_destinationColorSpace; KoColorConversionTransformation::Intent m_renderingIntent; KoColorConversionTransformation::ConversionFlags m_conversionFlags; }; class KisOpenGLUpdateInfo; typedef KisSharedPtr KisOpenGLUpdateInfoSP; class KisOpenGLUpdateInfo : public KisUpdateInfo { public: KisOpenGLUpdateInfo(); KisTextureTileUpdateInfoSPList tileList; QRect dirtyViewportRect() override; QRect dirtyImageRect() const override; void assignDirtyImageRect(const QRect &rect); void assignLevelOfDetail(int lod); int levelOfDetail() const override; bool tryMergeWith(const KisOpenGLUpdateInfo& rhs); private: QRect m_dirtyImageRect; int m_levelOfDetail; }; class KisPPUpdateInfo : public KisUpdateInfo { public: enum TransferType { DIRECT, PATCH }; QRect dirtyViewportRect() override; QRect dirtyImageRect() const override; int levelOfDetail() const override; /** * The rect that was reported by KisImage as dirty */ QRect dirtyImageRectVar; /** - * Rect of KisImage corresponding to @viewportRect. + * Rect of KisImage corresponding to @ref viewportRect . * It is cropped and aligned corresponding to the canvas. */ QRect imageRect; /** - * Rect of canvas widget corresponding to @imageRect + * Rect of canvas widget corresponding to @ref imageRect */ QRectF viewportRect; qreal scaleX; qreal scaleY; /** * Defines the way the source image is painted onto * prescaled QImage */ TransferType transfer; /** * Render hints for painting the direct painting/patch painting */ QPainter::RenderHints renderHints; /** * The number of additional pixels those should be added * to the patch */ qint32 borderWidth; /** * Used for temporary storage of KisImage's data * by KisProjectionCache */ KisImagePatch patch; }; class KisMarkerUpdateInfo : public KisUpdateInfo { public: enum Type { StartBatch = 0, EndBatch, BlockLodUpdates, UnblockLodUpdates, }; public: KisMarkerUpdateInfo(Type type, const QRect &dirtyImageRect); Type type() const; QRect dirtyImageRect() const override; int levelOfDetail() const override; private: Type m_type; QRect m_dirtyImageRect; }; #endif /* KIS_UPDATE_INFO_H_ */ diff --git a/libs/ui/dialogs/kis_dlg_adj_layer_props.h b/libs/ui/dialogs/kis_dlg_adj_layer_props.h index 384305abe4..07c4a09525 100644 --- a/libs/ui/dialogs/kis_dlg_adj_layer_props.h +++ b/libs/ui/dialogs/kis_dlg_adj_layer_props.h @@ -1,78 +1,83 @@ /* * Copyright (c) 2006 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_DLG_ADJ_LAYER_PROPS_H #define KIS_DLG_ADJ_LAYER_PROPS_H #include class QLineEdit; class KisFilter; class KisFilterConfiguration; class KisConfigWidget; class KisNodeFilterInterface; class KisViewManager; #include "kis_types.h" /** * Create a new adjustment layer. */ class KisDlgAdjLayerProps : public KoDialog { Q_OBJECT public: /** * Create a new adjustmentlayer dialog * + * @param node the node + * @param nfi the node filter interface + * @param paintDevice the painting device + * @param view the view manager + * @param configuration filter configuration * @param layerName the name of the adjustment layer * @param caption the caption for the dialog -- create or properties * @param parent the widget parent of this dialog * @param name the QObject name, if any */ KisDlgAdjLayerProps(KisNodeSP node, KisNodeFilterInterface *nfi, KisPaintDeviceSP paintDevice, KisViewManager *view, KisFilterConfigurationSP configuration, const QString & layerName, const QString & caption, QWidget *parent = 0, const char *name = 0); KisFilterConfigurationSP filterConfiguration() const; QString layerName() const; private Q_SLOTS: void slotNameChanged(const QString &); void slotConfigChanged(); private: KisNodeSP m_node; KisPaintDeviceSP m_paintDevice; KisConfigWidget *m_currentConfigWidget; KisFilter *m_currentFilter; KisFilterConfigurationSP m_currentConfiguration; QLineEdit *m_layerName; KisNodeFilterInterface *m_nodeFilterInterface; }; #endif // KIS_DLG_ADJ_LAYER_PROPS_H diff --git a/libs/ui/dialogs/kis_dlg_adjustment_layer.h b/libs/ui/dialogs/kis_dlg_adjustment_layer.h index 8c583f533f..015b41f034 100644 --- a/libs/ui/dialogs/kis_dlg_adjustment_layer.h +++ b/libs/ui/dialogs/kis_dlg_adjustment_layer.h @@ -1,79 +1,81 @@ /* * Copyright (c) 2006 Boudewijn Rempt * Copyright (c) 2008 Cyrille Berger * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KISDLGAdjustMENTLAYER_H #define KISDLGAdjustMENTLAYER_H #include #include class KisFilterConfiguration; class KisNodeFilterInterface; class KisViewManager; #include "kis_types.h" #include "ui_wdgfilternodecreation.h" /** * Create a new adjustment layer. */ class KisDlgAdjustmentLayer : public KoDialog { Q_OBJECT public: /** * Create a new adjustmentlayer dialog * - * @param layerName the name of the adjustment layer + * @param node the name of the adjustment node + * @param nfi filter interface * @param paintDevice the paint device that is used as source for the preview + * @param layerName the name of the layer * @param caption the caption for the dialog -- create or properties + * @param view the view manager * @param parent the widget parent of this dialog - * @param name the QObject name, if any */ KisDlgAdjustmentLayer(KisNodeSP node, KisNodeFilterInterface* nfi, KisPaintDeviceSP paintDevice, const QString & layerName, const QString & caption, KisViewManager *view, QWidget *parent = 0); ~KisDlgAdjustmentLayer() override; KisFilterConfigurationSP filterConfiguration() const; QString layerName() const; public Q_SLOTS: void adjustSize(); protected Q_SLOTS: void slotNameChanged(const QString &); void slotConfigChanged(); void slotFilterWidgetSizeChanged(); private: KisNodeSP m_node; KisNodeFilterInterface *m_nodeFilterInterface; Ui::WdgFilterNodeCreation wdgFilterNodeCreation; KisFilterConfigurationSP m_currentFilter; bool m_customName; QString m_layerName; }; #endif diff --git a/libs/ui/dialogs/kis_dlg_file_layer.h b/libs/ui/dialogs/kis_dlg_file_layer.h index b7d83aa686..df34cd1650 100644 --- a/libs/ui/dialogs/kis_dlg_file_layer.h +++ b/libs/ui/dialogs/kis_dlg_file_layer.h @@ -1,63 +1,64 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2013 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KIS_DLG_FILE_LAYER_H #define KIS_DLG_FILE_LAYER_H #include #include #include #include "ui_wdgdlgfilelayer.h" /** * Create a new file layer */ class KisDlgFileLayer : public KoDialog { public: Q_OBJECT public: /** * Create a new file layer + * @param basePath the base path of the layer * @param name the proposed name for this layer * @param parent the widget parent of this dialog */ KisDlgFileLayer(const QString &basePath, const QString &name, QWidget *parent = 0); QString fileName() const; QString layerName() const; KisFileLayer::ScalingMethod scaleToImageResolution() const; void setFileName(QString fileName); void setScalingMethod(KisFileLayer::ScalingMethod method); protected Q_SLOTS: void slotNameChanged(const QString &); private: Ui_WdgDlgFileLayer dlgWidget; QString m_basePath; }; #endif diff --git a/libs/ui/dialogs/kis_dlg_generator_layer.h b/libs/ui/dialogs/kis_dlg_generator_layer.h index d0c9df3454..252d3bd247 100644 --- a/libs/ui/dialogs/kis_dlg_generator_layer.h +++ b/libs/ui/dialogs/kis_dlg_generator_layer.h @@ -1,63 +1,64 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2008 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KIS_DLG_GENERATORLAYER_H #define KIS_DLG_GENERATORLAYER_H #include #include class KisFilterConfiguration; class KisViewManager; #include "ui_wdgdlggeneratorlayer.h" #include /** * Create a new generator layer */ class KisDlgGeneratorLayer : public KoDialog { public: Q_OBJECT public: /** * Create a new generator layer * @param name the proposed name for this layer + * @param view the view manager * @param parent the widget parent of this dialog */ KisDlgGeneratorLayer(const QString & name, KisViewManager *view, QWidget *parent); void setConfiguration(const KisFilterConfigurationSP config); KisFilterConfigurationSP configuration() const; QString layerName() const; protected Q_SLOTS: void slotNameChanged(const QString &); private: Ui_WdgDlgGeneratorLayer dlgWidget; bool m_customName; bool m_freezeName; }; #endif diff --git a/libs/ui/input/config/kis_input_button.h b/libs/ui/input/config/kis_input_button.h index b9ae279778..31d91b8583 100644 --- a/libs/ui/input/config/kis_input_button.h +++ b/libs/ui/input/config/kis_input_button.h @@ -1,143 +1,143 @@ /* * This file is part of the KDE project * Copyright (C) 2013 Arjen Hiemstra * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KISINPUTBUTTON_H #define KISINPUTBUTTON_H #include #include "input/kis_shortcut_configuration.h" /** * \brief A button that can detect input and will store its value. * * This button, when pressed, will detect input based on what type has been set. * It is mainly intended for shortcut configuration, that is, picking some input that is * later reused for shortcuts or similar. * */ class KisInputButton : public QPushButton { Q_OBJECT public: /** * The type of button. */ enum ButtonType { MouseType, ///< Detect and store any combination of pressed mouse buttons. KeyType, ///< Detect and store any combination of key presses. WheelType, ///< Detect and store mouse wheel movement. }; /** * Constructor. */ explicit KisInputButton(QWidget *parent = 0); /** * Destructor. */ ~KisInputButton() override; /** * \return The type of input this button detects. */ ButtonType type() const; /** * Set the type of input this button should detect. * * \param newType The type of input to detect. */ void setType(ButtonType newType); /** * \return The list of keys that was detected. Only applicable when type is `KeyType`. */ QList keys() const; /** * Set the list of keys to display. * * This is mostly intended to make sure the button displays the right keys when viewed * in a dialog or similar UI. * * Only applicable when type is `KeyType`. * * \param newKeys The list of keys to display. */ void setKeys(const QList &newKeys); /** * \return The mouse buttons that were detected. Only applicable when type is `MouseType`. */ Qt::MouseButtons buttons() const; /** * Set the mouse buttons to display. * * This is mostly intended to make sure the button displays the right buttons when viewed * in a dialog or similar UI. * * Only applicable when type is `MouseType`. * * \param newButtons The mouse buttons to display. */ void setButtons(Qt::MouseButtons newButtons); /** * \return The mouse wheel movement that was detected. Only applicable when type is `WheelType`. */ KisShortcutConfiguration::MouseWheelMovement wheel() const; /** * Set the mouse wheel movement to display. * * This is mostly intended to make sure the button displays the right wheel movement when * viewed in a dialog or similar UI. * * Only applicable when type is `WheelType`. * - * \param newButtons The wheel movement to display. + * \param wheel The wheel movement to display. */ void setWheel(KisShortcutConfiguration::MouseWheelMovement wheel); public Q_SLOTS: /** * Clear all detected input and reset the button to an empty state. */ void clear(); Q_SIGNALS: /** * Emitted whenever one of the values (keys, buttons, wheel) changes. */ void dataChanged(); protected: void mousePressEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *) override; void wheelEvent(QWheelEvent *event) override; void keyPressEvent(QKeyEvent *event) override; void keyReleaseEvent(QKeyEvent *event) override; private Q_SLOTS: void reset(); private: class Private; Private *const d; }; #endif // KISINPUTBUTTON_H diff --git a/libs/ui/input/wintab/kis_tablet_support_win.cpp b/libs/ui/input/wintab/kis_tablet_support_win.cpp index 93d3504624..f977bdfa5e 100644 --- a/libs/ui/input/wintab/kis_tablet_support_win.cpp +++ b/libs/ui/input/wintab/kis_tablet_support_win.cpp @@ -1,990 +1,990 @@ /* * Copyright (c) 2013 Digia Plc and/or its subsidiary(-ies). * Copyright (c) 2013 Boudewijn Rempt * Copyright (c) 2013 Dmitry Kazakov * Copyright (c) 2015 Michael Abrahams * Copyright (c) 2015 The Qt Company Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 "kis_tablet_support_win_p.h" #include "kis_tablet_support_win.h" #include #include #include #include // #include // #include // #include #include #include #include #include #include #define Q_PI M_PI #include #include // For "inline tool switches" #include #include #include "kis_screen_size_choice_dialog.h" // NOTE: we stub out qwindowcontext.cpp::347 to disable Qt's own tablet support. // Note: The definition of the PACKET structure in pktdef.h depends on this define. #define PACKETDATA (PK_X | PK_Y | PK_BUTTONS | PK_TIME | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION | PK_CURSOR | PK_Z) #include "pktdef.h" QT_BEGIN_NAMESPACE enum { PacketMode = 0, TabletPacketQSize = 128, DeviceIdMask = 0xFF6, // device type mask && device color mask CursorTypeBitMask = 0x0F06 // bitmask to find the specific cursor type (see Wacom FAQ) }; /* * * Krita extensions begin here * * */ QWindowsTabletSupport *QTAB = 0; static QPointer targetWindow = 0; //< Window receiving last tablet event static QPointer qt_tablet_target = 0; //< Widget receiving last tablet event static bool dialogOpen = false; //< KisTabletSupportWin is not a Q_OBJECT and can't accept dialog signals HWND createDummyWindow(const QString &className, const wchar_t *windowName, WNDPROC wndProc) { if (!wndProc) wndProc = DefWindowProc; WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = wndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = (HINSTANCE)GetModuleHandle(0); wc.hCursor = 0; wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW); wc.hIcon = 0; wc.hIconSm = 0; wc.lpszMenuName = 0; wc.lpszClassName = (wchar_t*)className.utf16(); ATOM atom = RegisterClassEx(&wc); if (!atom) qErrnoWarning("Registering tablet fake window class failed."); return CreateWindowEx(0, (wchar_t*)className.utf16(), windowName, WS_OVERLAPPED, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_MESSAGE, NULL, (HINSTANCE)GetModuleHandle(0), NULL); } void printContext(const LOGCONTEXT &lc) { dbgTablet << "# Getting current context data:"; dbgTablet << ppVar(lc.lcName); dbgTablet << ppVar(lc.lcDevice); dbgTablet << ppVar(lc.lcInOrgX); dbgTablet << ppVar(lc.lcInOrgY); dbgTablet << ppVar(lc.lcInExtX); dbgTablet << ppVar(lc.lcInExtY); dbgTablet << ppVar(lc.lcOutOrgX); dbgTablet << ppVar(lc.lcOutOrgY); dbgTablet << ppVar(lc.lcOutExtX); dbgTablet << ppVar(lc.lcOutExtY); dbgTablet << ppVar(lc.lcSysOrgX); dbgTablet << ppVar(lc.lcSysOrgY); dbgTablet << ppVar(lc.lcSysExtX); dbgTablet << ppVar(lc.lcSysExtY); dbgTablet << "Qt Desktop Geometry" << QApplication::desktop()->geometry(); } static QRect mapToNative(const QRect &qRect, int m_factor) { return QRect(qRect.x() * m_factor, qRect.y() * m_factor, qRect.width() * m_factor, qRect.height() * m_factor); } static inline QEvent::Type mouseEventType(QEvent::Type t) { return (t == QEvent::TabletMove ? QEvent::MouseMove : t == QEvent::TabletPress ? QEvent::MouseButtonPress : t == QEvent::TabletRelease ? QEvent::MouseButtonRelease : QEvent::None); } static inline bool isMouseEventType(QEvent::Type t) { return (t == QEvent::MouseMove || t == QEvent::MouseButtonPress || t == QEvent::MouseButtonRelease); } static QPoint mousePosition() { POINT p; GetCursorPos(&p); return QPoint(p.x, p.y); } QWindowsWinTab32DLL QWindowsTabletSupport::m_winTab32DLL; bool KisTabletSupportWin::init() { if (!QWindowsTabletSupport::m_winTab32DLL.init()) { qWarning() << "Failed to initialize Wintab"; return false; } QTAB = QWindowsTabletSupport::create(); // Refresh tablet context after tablet rotated, screen added, etc. QObject::connect(qApp->primaryScreen(), &QScreen::geometryChanged, [=](const QRect & geometry){ delete QTAB; QTAB = QWindowsTabletSupport::create(); }); return true; } // Derived from qwidgetwindow. // // The work done by processTabletEvent from qguiapplicationprivate is divided // between here and translateTabletPacketEvent. static void handleTabletEvent(QWidget *windowWidget, const QPointF &local, const QPointF &global, int device, int pointerType, Qt::MouseButton button, Qt::MouseButtons buttons, qreal pressure,int xTilt, int yTilt, qreal tangentialPressure, qreal rotation, int z, qint64 uniqueId, Qt::KeyboardModifiers modifiers, QEvent::Type type, LONG time) { // Lock in target window if (type == QEvent::TabletPress) { targetWindow = windowWidget; dbgInput << "Locking target window" << targetWindow; } else if ((type == QEvent::TabletRelease || buttons == Qt::NoButton) && (targetWindow != 0)) { dbgInput << "Releasing target window" << targetWindow; targetWindow = 0; } if (!windowWidget) // Should never happen return; // We do this instead of constructing the event e beforehand const QPoint localPos = local.toPoint(); const QPoint globalPos = global.toPoint(); if (type == QEvent::TabletPress) { QWidget *widget = windowWidget->childAt(localPos); if (!widget) widget = windowWidget; qt_tablet_target = widget; } QWidget *finalDestination = qt_tablet_target; if (!finalDestination) { finalDestination = windowWidget->childAt(localPos); } if ((type == QEvent::TabletRelease || buttons == Qt::NoButton) && (qt_tablet_target != 0)) { dbgInput << "releasing tablet target" << qt_tablet_target; qt_tablet_target = 0; } if (finalDestination) { // The event was specified relative to windowWidget, so we remap it QPointF delta = global - globalPos; QPointF mapped = finalDestination->mapFromGlobal(global.toPoint()) + delta; QTabletEvent ev(type, mapped, global, device, pointerType, pressure, xTilt, yTilt, tangentialPressure, rotation, z, modifiers, uniqueId, button, buttons); ev.setTimestamp(time); QGuiApplication::sendEvent(finalDestination, &ev); if (ev.isAccepted()) { // dbgTablet << "Tablet event" << type << "accepted" << "by target widget" << finalDestination; } else { // Turn off eventEater send a synthetic mouse event. // dbgTablet << "Tablet event" << type << "rejected; sending mouse event to" << finalDestination; qt_tablet_target = 0; // We shouldn't ever get a widget accepting a tablet event from this // call, so we won't worry about any interactions with our own // widget-locking code. // QWindow *target = platformScreen->topLevelAt(globalPos); // if (!target) return; // QPointF windowLocal = global - QPointF(target->mapFromGlobal(QPoint())) + delta; // QWindowSystemInterface::handleTabletEvent(target, ev.timestamp(), windowLocal, // global, device, pointerType, // buttons, pressure, xTilt, yTilt, // tangentialPressure, rotation, z, // uniqueId, modifiers); } } else { qt_tablet_target = 0; targetWindow = 0; } } /** * This is a default implementation of a class for converting the * WinTab value of the buttons pressed to the Qt buttons. This class * may be substituted from the UI. */ struct DefaultButtonsConverter { void convert(DWORD btnOld, DWORD btnNew, Qt::MouseButton *button, Qt::MouseButtons *buttons, const QWindowsTabletDeviceData &tdd) { int pressedButtonValue = btnNew ^ btnOld; *button = buttonValueToEnum(pressedButtonValue, tdd); *buttons = Qt::NoButton; for (int i = 0; i < 3; i++) { int btn = 0x1 << i; if (btn & btnNew) { Qt::MouseButton convertedButton = buttonValueToEnum(btn, tdd); *buttons |= convertedButton; /** * If a button that is present in hardware input is * mapped to a Qt::NoButton, it means that it is going * to be eaten by the driver, for example by its * "Pan/Scroll" feature. Therefore we shouldn't handle * any of the events associated to it. So just return * Qt::NoButton here. */ if (convertedButton == Qt::NoButton) { /** * Sometimes the driver-handled shortcuts are just * keyboard modifiers, so ideally we should handle * them as well. The problem is that we cannot * know if the shortcut was a pan/zoom action or a * shortcut. So here we use a "hackish" approach. * We just check if any modifier has been pressed * and, if so, pass the button to Krita. Of * course, if the driver uses some really complex * shortcuts like "Shift + stylus btn" to generate * some recorded shortcut, it will not work. But I * guess it will be ok for the most of the * usecases. * * WARNING: this hack will *not* work if you bind * any non-modifier key to the stylus * button, e.g. Space. */ const Qt::KeyboardModifiers keyboardModifiers = QApplication::queryKeyboardModifiers(); if (KisTabletDebugger::instance()->shouldEatDriverShortcuts() || keyboardModifiers == Qt::NoModifier) { *button = Qt::NoButton; *buttons = Qt::NoButton; break; } } } } } private: Qt::MouseButton buttonValueToEnum(DWORD button, const QWindowsTabletDeviceData &tdd) { const int leftButtonValue = 0x1; const int middleButtonValue = 0x2; const int rightButtonValue = 0x4; const int doubleClickButtonValue = 0x7; button = tdd.buttonsMap.value(button); return button == leftButtonValue ? Qt::LeftButton : button == rightButtonValue ? Qt::RightButton : button == doubleClickButtonValue ? Qt::MiddleButton : button == middleButtonValue ? Qt::MiddleButton : button ? Qt::LeftButton /* fallback item */ : Qt::NoButton; } }; static DefaultButtonsConverter *globalButtonsConverter = new DefaultButtonsConverter(); /* * * Krita extensions end here * * */ // This is the WndProc for a single additional hidden window used to collect tablet events. extern "C" LRESULT QT_WIN_CALLBACK qWindowsTabletSupportWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WT_PROXIMITY: if (QTAB->translateTabletProximityEvent(wParam, lParam)) return 0; break; case WT_PACKET: if (QTAB->translateTabletPacketEvent()) return 0; break; } return DefWindowProc(hwnd, message, wParam, lParam); } // Scale tablet coordinates to screen coordinates. static inline int sign(int x) { return x >= 0 ? 1 : -1; } inline QPointF QWindowsTabletDeviceData::scaleCoordinates(int coordX, int coordY, const QRect &targetArea) const { const int targetX = targetArea.x(); const int targetY = targetArea.y(); const int targetWidth = targetArea.width(); const int targetHeight = targetArea.height(); const qreal x = sign(targetWidth) == sign(maxX) ? ((coordX - minX) * qAbs(targetWidth) / qAbs(qreal(maxX - minX))) + targetX : ((qAbs(maxX) - (coordX - minX)) * qAbs(targetWidth) / qAbs(qreal(maxX - minX))) + targetX; const qreal y = sign(targetHeight) == sign(maxY) ? ((coordY - minY) * qAbs(targetHeight) / qAbs(qreal(maxY - minY))) + targetY : ((qAbs(maxY) - (coordY - minY)) * qAbs(targetHeight) / qAbs(qreal(maxY - minY))) + targetY; return QPointF(x, y); } /*! - \class QWindowsWinTab32DLL QWindowsTabletSupport + \class QWindowsWinTab32DLL \brief Functions from wintabl32.dll shipped with WACOM tablets used by QWindowsTabletSupport. \internal \ingroup qt-lighthouse-win */ bool QWindowsWinTab32DLL::init() { if (wTInfo) return true; QLibrary library(QStringLiteral("wintab32")); if (!library.load()) { qWarning() << QString("Could not load wintab32 dll: %1").arg(library.errorString()); return false; } wTOpen = (PtrWTOpen) library.resolve("WTOpenW"); wTClose = (PtrWTClose) library.resolve("WTClose"); wTInfo = (PtrWTInfo) library.resolve("WTInfoW"); wTEnable = (PtrWTEnable) library.resolve("WTEnable"); wTOverlap = (PtrWTOverlap) library.resolve("WTOverlap"); wTPacketsGet = (PtrWTPacketsGet) library.resolve("WTPacketsGet"); wTGet = (PtrWTGet) library.resolve("WTGetW"); wTQueueSizeGet = (PtrWTQueueSizeGet) library.resolve("WTQueueSizeGet"); wTQueueSizeSet = (PtrWTQueueSizeSet) library.resolve("WTQueueSizeSet"); if (wTOpen && wTClose && wTInfo && wTEnable && wTOverlap && wTPacketsGet && wTQueueSizeGet && wTQueueSizeSet) { return true; } qWarning() << "Could not resolve the following symbols:\n" << "\t wTOpen" << wTOpen << "\n" << "\t wtClose" << wTClose << "\n" << "\t wtInfo" << wTInfo << "\n" << "\t wTEnable" << wTEnable << "\n" << "\t wTOverlap" << wTOverlap << "\n" << "\t wTPacketsGet" << wTPacketsGet << "\n" << "\t wTQueueSizeGet" << wTQueueSizeGet << "\n" << "\t wTQueueSizeSet" << wTQueueSizeSet << "\n"; return false; } /*! \class QWindowsTabletSupport \brief Tablet support for Windows. Support for WACOM tablets. \sa http://www.wacomeng.com/windows/docs/Wintab_v140.htm \internal \since 5.2 \ingroup qt-lighthouse-win */ QWindowsTabletSupport::QWindowsTabletSupport(HWND window, HCTX context) : m_window(window) , m_context(context) , m_absoluteRange(20) , m_tiltSupport(false) , m_currentDevice(-1) { AXIS orientation[3]; // Some tablets don't support tilt, check if it is possible, if (QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEVICES, DVC_ORIENTATION, &orientation)) m_tiltSupport = orientation[0].axResolution && orientation[1].axResolution; } QWindowsTabletSupport::~QWindowsTabletSupport() { QWindowsTabletSupport::m_winTab32DLL.wTClose(m_context); DestroyWindow(m_window); } QWindowsTabletSupport *QWindowsTabletSupport::create() { const HWND window = createDummyWindow(QStringLiteral("TabletDummyWindow"), L"TabletDummyWindow", qWindowsTabletSupportWndProc); LOGCONTEXT lcMine; // build our context from the default context QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEFSYSCTX, 0, &lcMine); // Go for the raw coordinates, the tablet event will return good stuff. The // defaults for lcOut rectangle are the desktop dimensions in pixels, which // means Wintab will do lossy rounding. Instead we specify this trivial // scaling for the output context, then do the scaling ourselves later to // obtain higher resolution coordinates. lcMine.lcOptions |= CXO_MESSAGES | CXO_CSRMESSAGES; lcMine.lcPktData = lcMine.lcMoveMask = PACKETDATA; lcMine.lcPktMode = PacketMode; lcMine.lcOutOrgX = 0; lcMine.lcOutExtX = lcMine.lcInExtX; lcMine.lcOutOrgY = 0; lcMine.lcOutExtY = -lcMine.lcInExtY; const HCTX context = QWindowsTabletSupport::m_winTab32DLL.wTOpen(window, &lcMine, true); if (!context) { dbgTablet << __FUNCTION__ << "Unable to open tablet."; DestroyWindow(window); return 0; } // Set the size of the Packet Queue to the correct size const int currentQueueSize = QWindowsTabletSupport::m_winTab32DLL.wTQueueSizeGet(context); if (currentQueueSize != TabletPacketQSize) { if (!QWindowsTabletSupport::m_winTab32DLL.wTQueueSizeSet(context, TabletPacketQSize)) { if (!QWindowsTabletSupport::m_winTab32DLL.wTQueueSizeSet(context, currentQueueSize)) { qWarning() << "Unable to set queue size on tablet. The tablet will not work."; QWindowsTabletSupport::m_winTab32DLL.wTClose(context); DestroyWindow(window); return 0; } // cannot restore old size } // cannot set } // mismatch dbgTablet << "Opened tablet context " << context << " on window " << window << "changed packet queue size " << currentQueueSize << "->" << TabletPacketQSize; return new QWindowsTabletSupport(window, context); } unsigned QWindowsTabletSupport::options() const { UINT result = 0; m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_CTXOPTIONS, &result); return result; } QString QWindowsTabletSupport::description() const { const unsigned size = m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_WINTABID, 0); if (!size) return QString(); QVarLengthArray winTabId(size + 1); m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_WINTABID, winTabId.data()); WORD implementationVersion = 0; m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_IMPLVERSION, &implementationVersion); WORD specificationVersion = 0; m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_SPECVERSION, &specificationVersion); const unsigned opts = options(); QString result = QString::fromLatin1("%1 specification: v%2.%3 implementation: v%4.%5 options: 0x%6") .arg(QString::fromWCharArray(winTabId.data())) .arg(specificationVersion >> 8).arg(specificationVersion & 0xFF) .arg(implementationVersion >> 8).arg(implementationVersion & 0xFF) .arg(opts, 0, 16); if (opts & CXO_MESSAGES) result += QStringLiteral(" CXO_MESSAGES"); if (opts & CXO_CSRMESSAGES) result += QStringLiteral(" CXO_CSRMESSAGES"); if (m_tiltSupport) result += QStringLiteral(" tilt"); return result; } void QWindowsTabletSupport::notifyActivate() { // Cooperate with other tablet applications, but when we get focus, I want to use the tablet. const bool result = QWindowsTabletSupport::m_winTab32DLL.wTEnable(m_context, true) && QWindowsTabletSupport::m_winTab32DLL.wTOverlap(m_context, true); dbgTablet << __FUNCTION__ << result; } static inline int indexOfDevice(const QVector &devices, qint64 uniqueId) { for (int i = 0; i < devices.size(); ++i) if (devices.at(i).uniqueId == uniqueId) return i; return -1; } static inline QTabletEvent::TabletDevice deviceType(const UINT cursorType) { if (((cursorType & 0x0006) == 0x0002) && ((cursorType & CursorTypeBitMask) != 0x0902)) return QTabletEvent::Stylus; if (cursorType == 0x4020) // Surface Pro 2 tablet device return QTabletEvent::Stylus; switch (cursorType & CursorTypeBitMask) { case 0x0802: return QTabletEvent::Stylus; case 0x0902: return QTabletEvent::Airbrush; case 0x0004: return QTabletEvent::FourDMouse; case 0x0006: return QTabletEvent::Puck; case 0x0804: return QTabletEvent::RotationStylus; default: break; } return QTabletEvent::NoDevice; }; static inline QTabletEvent::PointerType pointerType(unsigned pkCursor) { switch (pkCursor % 3) { // %3 for dual track case 0: return QTabletEvent::Cursor; case 1: return QTabletEvent::Pen; case 2: return QTabletEvent::Eraser; default: break; } return QTabletEvent::UnknownPointer; } QDebug operator<<(QDebug d, const QWindowsTabletDeviceData &t) { d << "TabletDevice id:" << t.uniqueId << " pressure: " << t.minPressure << ".." << t.maxPressure << " tan pressure: " << t.minTanPressure << ".." << t.maxTanPressure << " area:" << t.minX << t.minY << t.minZ << ".." << t.maxX << t.maxY << t.maxZ << " device " << t.currentDevice << " pointer " << t.currentPointerType; return d; } QWindowsTabletDeviceData QWindowsTabletSupport::tabletInit(const quint64 uniqueId, const UINT cursorType) const { QWindowsTabletDeviceData result; result.uniqueId = uniqueId; /* browse WinTab's many info items to discover pressure handling. */ AXIS axis; LOGCONTEXT lc; /* get the current context for its device variable. */ QWindowsTabletSupport::m_winTab32DLL.wTGet(m_context, &lc); if (KisTabletDebugger::instance()->initializationDebugEnabled()) { printContext(lc); } /* get the size of the pressure axis. */ QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEVICES + lc.lcDevice, DVC_NPRESSURE, &axis); result.minPressure = int(axis.axMin); result.maxPressure = int(axis.axMax); QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEVICES + lc.lcDevice, DVC_TPRESSURE, &axis); result.minTanPressure = int(axis.axMin); result.maxTanPressure = int(axis.axMax); result.minX = int(lc.lcOutOrgX); result.maxX = int(lc.lcOutExtX) + int(lc.lcOutOrgX); result.minY = int(lc.lcOutOrgY); result.maxY = -int(lc.lcOutExtY) + int(lc.lcOutOrgY); // These are set to 0 when we opened the tablet context in QWindowsTabletSupport::create KIS_SAFE_ASSERT_RECOVER_NOOP(lc.lcOutOrgX == 0); KIS_SAFE_ASSERT_RECOVER_NOOP(lc.lcOutOrgY == 0); result.maxZ = int(lc.lcOutExtZ) - int(lc.lcOutOrgZ); result.currentDevice = deviceType(cursorType); // Define a rectangle representing the whole screen as seen by Wintab. QRect qtDesktopRect = QApplication::desktop()->geometry(); QRect wintabDesktopRect(lc.lcSysOrgX, lc.lcSysOrgY, lc.lcSysExtX, lc.lcSysExtY); qDebug() << ppVar(qtDesktopRect); qDebug() << ppVar(wintabDesktopRect); // Show screen choice dialog if (!dialogOpen) { KisScreenSizeChoiceDialog dlg(0, wintabDesktopRect, qtDesktopRect); KisExtendedModifiersMapper mapper; KisExtendedModifiersMapper::ExtendedModifiers modifiers = mapper.queryExtendedModifiers(); if (modifiers.contains(Qt::Key_Shift) || (!dlg.canUseDefaultSettings() && qtDesktopRect != wintabDesktopRect)) { dialogOpen = true; dlg.exec(); } result.virtualDesktopArea = dlg.screenRect(); dialogOpen = false; } else { // This branch should've been explicitly prevented. KIS_SAFE_ASSERT_RECOVER_NOOP(!dialogOpen); warnTablet << "Trying to init a WinTab device while screen resolution dialog is active, this should not happen!"; warnTablet << "Tablet coordinates could be wrong as a result."; result.virtualDesktopArea = qtDesktopRect; } return result; }; bool QWindowsTabletSupport::translateTabletProximityEvent(WPARAM /* wParam */, LPARAM lParam) { if (dialogOpen) { // tabletInit(...) may show the screen resolution dialog and is blocking. // During this period, don't process any tablet events at all. dbgTablet << "WinTab screen resolution dialog is active, ignoring WinTab proximity event"; return false; } auto sendProximityEvent = [&](QEvent::Type type) { QPointF emptyPos; qreal zero = 0.0; QTabletEvent e(type, emptyPos, emptyPos, 0, m_devices.at(m_currentDevice).currentPointerType, zero, 0, 0, zero, zero, 0, Qt::NoModifier, m_devices.at(m_currentDevice).uniqueId, Qt::NoButton, (Qt::MouseButtons)0); qApp->sendEvent(qApp, &e); }; if (!LOWORD(lParam)) { // dbgTablet << "leave proximity for device #" << m_currentDevice; sendProximityEvent(QEvent::TabletLeaveProximity); return true; } PACKET proximityBuffer[1]; // we are only interested in the first packet in this case const int totalPacks = QWindowsTabletSupport::m_winTab32DLL.wTPacketsGet(m_context, 1, proximityBuffer); if (!totalPacks) return false; UINT pkCursor = proximityBuffer[0].pkCursor; // initializing and updating the cursor should be done in response to // WT_CSRCHANGE. We do it in WT_PROXIMITY because some wintab never send // the event WT_CSRCHANGE even if asked with CXO_CSRMESSAGES tabletUpdateCursor(pkCursor); // dbgTablet << "enter proximity for device #" << m_currentDevice << m_devices.at(m_currentDevice); sendProximityEvent(QEvent::TabletEnterProximity); return true; } bool QWindowsTabletSupport::translateTabletPacketEvent() { static PACKET localPacketBuf[TabletPacketQSize]; // our own tablet packet queue. const int packetCount = QWindowsTabletSupport::m_winTab32DLL.wTPacketsGet(m_context, TabletPacketQSize, &localPacketBuf); if (!packetCount || m_currentDevice < 0 || dialogOpen) return false; // In contrast to Qt, these will not be "const" during our loop. // This is because the Surface Pro 3 may cause us to switch devices. QWindowsTabletDeviceData tabletData = m_devices.at(m_currentDevice); int currentDevice = tabletData.currentDevice; int currentPointerType = tabletData.currentPointerType; // static Qt::MouseButtons buttons = Qt::NoButton, btnOld, btnChange; static DWORD btnNew, btnOld, btnChange; // The tablet can be used in 2 different modes, depending on its settings: // 1) Absolute (pen) mode: // The coordinates are scaled to the virtual desktop (by default). The user // can also choose to scale to the monitor or a region of the screen. // When entering proximity, the tablet driver snaps the mouse pointer to the // tablet position scaled to that area and keeps it in sync. // 2) Relative (mouse) mode: // The pen follows the mouse. The constant 'absoluteRange' specifies the // manhattanLength difference for detecting if a tablet input device is in this mode, // in which case we snap the position to the mouse position. // It seems there is no way to find out the mode programmatically, the LOGCONTEXT orgX/Y/Ext // area is always the virtual desktop. static qreal dpr = 1.0; auto activeWindow = qApp->activeWindow(); if (activeWindow) { dpr = activeWindow->devicePixelRatio(); } const Qt::KeyboardModifiers keyboardModifiers = QApplication::queryKeyboardModifiers(); for (int i = 0; i < packetCount; ++i) { const PACKET &packet = localPacketBuf[i]; btnOld = btnNew; btnNew = localPacketBuf[i].pkButtons; btnChange = btnOld ^ btnNew; bool buttonPressed = btnChange && btnNew > btnOld; bool buttonReleased = btnChange && btnNew < btnOld; bool anyButtonsStillPressed = btnNew; Qt::MouseButton button = Qt::NoButton; Qt::MouseButtons buttons; globalButtonsConverter->convert(btnOld, btnNew, &button, &buttons, tabletData); QEvent::Type type = QEvent::TabletMove; if (buttonPressed && button != Qt::NoButton) { type = QEvent::TabletPress; } else if (buttonReleased && button != Qt::NoButton) { type = QEvent::TabletRelease; } const int z = currentDevice == QTabletEvent::FourDMouse ? int(packet.pkZ) : 0; // NOTE: we shouldn't postpone the tablet events like Qt does, because we // don't support mouse mode (which was the reason for introducing this // postponing). See bug 363284. QPointF globalPosF = tabletData.scaleCoordinates(packet.pkX, packet.pkY, tabletData.virtualDesktopArea); globalPosF /= dpr; // Convert from "native" to "device independent pixels." QPoint globalPos = globalPosF.toPoint(); // Find top-level window QWidget *w = targetWindow; // If we had a target already, use it. if (!w) { w = qApp->activePopupWidget(); if (!w) w = qApp->activeModalWidget(); if (!w) w = qApp->topLevelAt(globalPos); if (!w) continue; w = w->window(); } const QPoint localPos = w->mapFromGlobal(globalPos); const QPointF delta = globalPosF - globalPos; const QPointF localPosF = globalPosF + QPointF(localPos - globalPos) + delta; const qreal pressureNew = packet.pkButtons && (currentPointerType == QTabletEvent::Pen || currentPointerType == QTabletEvent::Eraser) ? m_devices.at(m_currentDevice).scalePressure(packet.pkNormalPressure) : qreal(0); const qreal tangentialPressure = currentDevice == QTabletEvent::Airbrush ? m_devices.at(m_currentDevice).scaleTangentialPressure(packet.pkTangentPressure) : qreal(0); int tiltX = 0; int tiltY = 0; qreal rotation = 0; if (m_tiltSupport) { // Convert from azimuth and altitude to x tilt and y tilt. What // follows is the optimized version. Here are the equations used: // X = sin(azimuth) * cos(altitude) // Y = cos(azimuth) * cos(altitude) // Z = sin(altitude) // X Tilt = arctan(X / Z) // Y Tilt = arctan(Y / Z) const double radAzim = (packet.pkOrientation.orAzimuth / 10.0) * (M_PI / 180); const double tanAlt = std::tan((std::abs(packet.pkOrientation.orAltitude / 10.0)) * (M_PI / 180)); const double degX = std::atan(std::sin(radAzim) / tanAlt); const double degY = std::atan(std::cos(radAzim) / tanAlt); tiltX = int(degX * (180 / M_PI)); tiltY = int(-degY * (180 / M_PI)); rotation = 360.0 - (packet.pkOrientation.orTwist / 10.0); if (rotation > 180.0) rotation -= 360.0; } // This is adds *a lot* of noise to the output log if (false) { dbgTablet << "Packet #" << (i+1) << '/' << packetCount << "button:" << packet.pkButtons << globalPosF << z << "to:" << w << localPos << "(packet" << packet.pkX << packet.pkY << ") dev:" << currentDevice << "pointer:" << currentPointerType << "P:" << pressureNew << "tilt:" << tiltX << ',' << tiltY << "tanP:" << tangentialPressure << "rotation:" << rotation; } // Reusable helper function. Better than compiler macros! auto sendTabletEvent = [&](QTabletEvent::Type t){ handleTabletEvent(w, localPosF, globalPosF, currentDevice, currentPointerType, button, buttons, pressureNew, tiltX, tiltY, tangentialPressure, rotation, z, m_devices.at(m_currentDevice).uniqueId, keyboardModifiers, t, packet.pkTime); }; /** * Workaround to deal with "inline" tool switches. * These are caused by the eraser trigger button on the Surface Pro 3. * We shoot out a tabletUpdateCursor request and a switchInputDevice request. */ if (isSurfacePro3 && (packet.pkCursor != currentPkCursor)) { dbgTablet << "Got an inline tool switch."; // Send tablet release event. sendTabletEvent(QTabletEvent::TabletRelease); // Read the new cursor info. UINT pkCursor = packet.pkCursor; tabletUpdateCursor(pkCursor); // Update the local loop variables. tabletData = m_devices.at(m_currentDevice); currentDevice = deviceType(tabletData.currentDevice); currentPointerType = pointerType(pkCursor); sendTabletEvent(QTabletEvent::TabletPress); } sendTabletEvent(type); } // Loop over packets return true; } void QWindowsTabletSupport::tabletUpdateCursor(const int pkCursor) { UINT physicalCursorId; QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_CURSORS + pkCursor, CSR_PHYSID, &physicalCursorId); UINT cursorType; QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_CURSORS + pkCursor, CSR_TYPE, &cursorType); const qint64 uniqueId = (qint64(cursorType & DeviceIdMask) << 32L) | qint64(physicalCursorId); m_currentDevice = indexOfDevice(m_devices, uniqueId); if (m_currentDevice < 0) { m_currentDevice = m_devices.size(); m_devices.push_back(tabletInit(uniqueId, cursorType)); // Note: ideally we might check this button map for changes every // update. However there seems to be an issue with Wintab altering the // button map when the user right-clicks in Krita while another // application has focus. This forces Krita to load button settings only // once, when the tablet is first detected. // // See https://bugs.kde.org/show_bug.cgi?id=359561 BYTE logicalButtons[32]; memset(logicalButtons, 0, 32); m_winTab32DLL.wTInfo(WTI_CURSORS + pkCursor, CSR_SYSBTNMAP, &logicalButtons); m_devices[m_currentDevice].buttonsMap[0x1] = logicalButtons[0]; m_devices[m_currentDevice].buttonsMap[0x2] = logicalButtons[1]; m_devices[m_currentDevice].buttonsMap[0x4] = logicalButtons[2]; } m_devices[m_currentDevice].currentPointerType = pointerType(pkCursor); currentPkCursor = pkCursor; // Check tablet name to enable Surface Pro 3 workaround. #ifdef UNICODE if (!isSurfacePro3) { /** * Some really "nice" tablet drivers don't know that they are * supposed to return their name length when the buffer is * null and they try to write into it effectively causing a * suicide. So we cannot rely on it :( * * We workaround it by just allocating a big array and hoping * for the best. * * Failing tablets: * - Adesso Cybertablet M14 * - Peritab-302 * - Trust Tablet TB7300 * - VisTablet Realm Pro * - Aiptek 14000u (latest driver: v5.03, 2013-10-21) * - Genius G-Pen F350 * - Genius G-Pen 560 (supported on win7 only) */ // we cannot use the correct api :( // UINT nameLength = QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEVICES, DVC_NAME, 0); // 1024 chars should be enough for everyone! (c) UINT nameLength = 1024; TCHAR* dvcName = new TCHAR[nameLength + 1]; memset(dvcName, 0, sizeof(TCHAR) * nameLength); UINT writtenBytes = QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEVICES, DVC_NAME, dvcName); if (writtenBytes > sizeof(TCHAR) * nameLength) { qWarning() << "WINTAB WARNING: tablet name is too long!" << writtenBytes; // avoid crash when trying to read it dvcName[nameLength - 1] = (TCHAR)0; } QString qDvcName = QString::fromWCharArray((const wchar_t*)dvcName); dbgInput << "DVC_NAME =" << qDvcName; // Name changed between older and newer Surface Pro 3 drivers if (qDvcName == QString::fromLatin1("N-trig DuoSense device") || qDvcName == QString::fromLatin1("Microsoft device")) { dbgInput << "This looks like a Surface Pro 3. Enabling eraser workaround."; isSurfacePro3 = true; } delete[] dvcName; } #endif } QT_END_NAMESPACE diff --git a/libs/ui/kis_categorized_item_delegate.h b/libs/ui/kis_categorized_item_delegate.h index 13acfcd4d4..0268b27cf2 100644 --- a/libs/ui/kis_categorized_item_delegate.h +++ b/libs/ui/kis_categorized_item_delegate.h @@ -1,43 +1,43 @@ /* * Copyright (c) 2009 Cyrille Berger * Copyright (c) 2011 Silvio Heinrich * Copyright (c) 2014 Mohit Goyal * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _KIS_CATEGORIZED_ITEM_DELEGATE_H_ #define _KIS_CATEGORIZED_ITEM_DELEGATE_H_ #include #include #include /** - * This delegate draw categories using information from a \ref KCategorizedSortFilterProxyModel . + * This delegate draw categories using information from a QSortFilterProxyModel. */ class KRITAUI_EXPORT KisCategorizedItemDelegate: public QStyledItemDelegate { public: KisCategorizedItemDelegate(QObject *parent); void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override; QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override; private: void paintTriangle(QPainter* painter, qint32 x, qint32 y, qint32 size, bool rotate) const; mutable qint32 m_minimumItemHeight; }; #endif // _KIS_CATEGORIZED_ITEM_DELEGATE_H_ diff --git a/libs/ui/kis_deferred_signal.h b/libs/ui/kis_deferred_signal.h index 9b8181a5ab..4ea8c67f3a 100644 --- a/libs/ui/kis_deferred_signal.h +++ b/libs/ui/kis_deferred_signal.h @@ -1,71 +1,72 @@ /* * Copyright (c) 2014 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 __KIS_DEFERRED_SIGNAL_H #define __KIS_DEFERRED_SIGNAL_H #include #include /** - * \class KisDeferredSignal is used for calling a specified callback + * \class KisDeferredSignal + * \brief This class is used for calling a specified callback * function (which is a std::function) after a specified time * delay. The callback is called from the QTimer event, so the * usage of the class does not block the Qt's event loop. * * Usage: * * \code{.cpp} * * // prepare the callback function * std::function callback( * std::bind(&KisCanvas2::setMonitorProfile, this, * monitorProfile, renderingIntent, conversionFlags)); * * // create the timer connected to the function * KisDeferredSignal::deferSignal(1000, callback); * * \endcode * * TODO: rename KisDeferredSignal -> KisDeferredCallback */ class KisDeferredSignal : public QObject { Q_OBJECT public: using CallbackFunction = std::function; public: /** * Creates a timer which will call \p function after \p delay * milliseconds */ static void deferSignal(int delay, CallbackFunction function); private Q_SLOTS: void timeout(); private: KisDeferredSignal(int delay, CallbackFunction function); private: CallbackFunction m_function; }; #endif /* __KIS_DEFERRED_SIGNAL_H */ diff --git a/libs/ui/kis_image_manager.h b/libs/ui/kis_image_manager.h index ea4371345f..49d17d743b 100644 --- a/libs/ui/kis_image_manager.h +++ b/libs/ui/kis_image_manager.h @@ -1,75 +1,76 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2006 * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_IMAGE_MANAGER #define KIS_IMAGE_MANAGER #include #include #include #include class KisViewManager; class KisFilterStrategy; class KisActionManager; class KisView; class KRITAUI_EXPORT KisImageManager : public QObject { Q_OBJECT public: KisImageManager(KisViewManager * view); ~KisImageManager() override {} void setView(QPointerimageView); void setup(KisActionManager *actionManager); public Q_SLOTS: void slotImportLayerFromFile(); void slotImportLayerAsTransparencyMask(); void slotImportLayerAsFilterMask(); void slotImportLayerAsSelectionMask(); /** * Import an image as a layer. If there is more than * one layer in the image, import all of them as separate * layers. * * @param url the url to the image file + * @param layerType the layer type * @return the number of layers added */ qint32 importImage(const QUrl &url, const QString &layerType = "KisPaintLayer"); void resizeCurrentImage(qint32 w, qint32 h, qint32 xOffset, qint32 yOffset); void scaleCurrentImage(const QSize &size, qreal xres, qreal yres, KisFilterStrategy *filterStrategy); void rotateCurrentImage(double radians); void shearCurrentImage(double angleX, double angleY); void slotImageProperties(); void slotImageColor(); private: KisViewManager * m_view; }; #endif // KIS_IMAGE_MANAGER diff --git a/libs/ui/kis_model_index_converter_base.h b/libs/ui/kis_model_index_converter_base.h index 92ceef1884..a36c7d8511 100644 --- a/libs/ui/kis_model_index_converter_base.h +++ b/libs/ui/kis_model_index_converter_base.h @@ -1,78 +1,82 @@ /* * Copyright (c) 2011 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 __KIS_MODEL_INDEX_CONVERTER_BASE_H #define __KIS_MODEL_INDEX_CONVERTER_BASE_H #include #include "kritaui_export.h" class KisNodeDummy; /** * The base class for converting objects to/from QModelIndex used * in KisNodeModel and KisNodeDummy used in KisDummiesFacadeBase * (KisShapeController). * * This is not a trivial task, because the indexing of nodes is * reversed in KisNodeModel. */ class KRITAUI_EXPORT KisModelIndexConverterBase { public: virtual ~KisModelIndexConverterBase(); /** * Returns the dummy staying in the specified \p row of a \p parent - * May return null in case of incosistency + * May return null in case of inconsistency */ virtual KisNodeDummy* dummyFromRow(int row, QModelIndex parent) = 0; /** * Returns the dummy associated with the \p index * WARNING: \p index must be valid - * NOTE: cannot return null + * \note cannot return null */ virtual KisNodeDummy* dummyFromIndex(QModelIndex index) = 0; /** * Returns the index corresponding to the position of the \p dummy * in the model. Will return invalid index if the dummy should be hidden */ virtual QModelIndex indexFromDummy(KisNodeDummy *dummy) = 0; /** * Calculates the parent and the position in the model for newly created dummy + * \param parentDummy the dummy parent + * \param index the dummy index * \param newNodeMetaObjectType is a class name of a newly added node * This name is got from Qt's meta object system so you must * compare this value against a corresponding staticMetaObject * object only. * We do not pass a pointer to a real node to limit the access to * real nodes. - * Return whether the new dummy will be shown in the model + * \param parentIndex the parent index + * \param row the dummy row + * \return whether the new dummy will be shown in the model */ virtual bool indexFromAddedDummy(KisNodeDummy *parentDummy, int index, const QString &newNodeMetaObjectType, QModelIndex &parentIndex, int &row) = 0; /** * Returns the number of children of the given index of the model */ virtual int rowCount(QModelIndex parent) = 0; }; #endif /* __KIS_MODEL_INDEX_CONVERTER_BASE_H */ diff --git a/libs/ui/kis_node_view_color_scheme.cpp b/libs/ui/kis_node_view_color_scheme.cpp index 384a8d23fa..f875165465 100644 --- a/libs/ui/kis_node_view_color_scheme.cpp +++ b/libs/ui/kis_node_view_color_scheme.cpp @@ -1,194 +1,199 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 "kis_node_view_color_scheme.h" #include #include #include "krita_utils.h" #include #include #include Q_GLOBAL_STATIC(KisNodeViewColorScheme, s_instance) struct KisNodeViewColorScheme::Private { Private() { if (colorLabels.isEmpty()) { colorLabels << Qt::transparent; colorLabels << QColor(91,173,220); colorLabels << QColor(151,202,63); colorLabels << QColor(247,229,61); colorLabels << QColor(255,170,63); colorLabels << QColor(177,102,63); colorLabels << QColor(238,50,51); colorLabels << QColor(191,106,209); colorLabels << QColor(118,119,114); const QColor noLabelSetColor = qApp->palette().color(QPalette::Highlight); for (auto it = colorLabels.begin(); it != colorLabels.end(); ++it) { KritaUtils::dragColor(&(*it), noLabelSetColor, 0.35); } } } static QVector colorLabels; }; QVector KisNodeViewColorScheme::Private::colorLabels; KisNodeViewColorScheme::KisNodeViewColorScheme() : m_d(new Private) { } KisNodeViewColorScheme::~KisNodeViewColorScheme() { } KisNodeViewColorScheme* KisNodeViewColorScheme::instance() { return s_instance; } QColor KisNodeViewColorScheme::gridColor(const QStyleOptionViewItem &option, QTreeView *view) { const int gridHint = view->style()->styleHint(QStyle::SH_Table_GridLineColor, &option, view); const QColor gridColor = static_cast(gridHint); return gridColor; } int KisNodeViewColorScheme::visibilitySize() const { return 16; } int KisNodeViewColorScheme::visibilityMargin() const { return 2; } int KisNodeViewColorScheme::thumbnailSize() const { KisConfig cfg(true); return cfg.layerThumbnailSize(false); } int KisNodeViewColorScheme::thumbnailMargin() const { return 3; } int KisNodeViewColorScheme::decorationSize() const { return 12; } int KisNodeViewColorScheme::decorationMargin() const { return 1; } int KisNodeViewColorScheme::textMargin() const { return 2; } int KisNodeViewColorScheme::iconSize() const { return 16; } int KisNodeViewColorScheme::iconMargin() const { return 1; } int KisNodeViewColorScheme::border() const { return 1; } int KisNodeViewColorScheme::rowHeight() const { return border() + 2 * thumbnailMargin() + thumbnailSize(); } int KisNodeViewColorScheme::visibilityColumnWidth() const { return border() + 2 * visibilityMargin() + visibilitySize() + border(); } int KisNodeViewColorScheme::indentation() const { return 2 * thumbnailMargin() + thumbnailSize() + border(); } +QRect KisNodeViewColorScheme::relVisibilityRect() const +{ + return QRect(0, 0, + visibilitySize() + 2 * visibilityMargin() + 2 * border(), + visibilitySize() + 2 * visibilityMargin() + 1 * border()); +} + QRect KisNodeViewColorScheme::relThumbnailRect() const { - return QRect(-indentation(), - border(), - thumbnailSize() + 2 * thumbnailMargin(), - thumbnailSize() + 2 * thumbnailMargin()); + return QRect(0, 0, + thumbnailSize() + 2 * thumbnailMargin() + 2 * border(), + thumbnailSize() + 2 * thumbnailMargin() + 1 * border()); } QRect KisNodeViewColorScheme::relDecorationRect() const { - return QRect(border() + decorationMargin(), - border() + decorationMargin(), - decorationSize(), - decorationSize()); + return QRect(0, 0, + decorationSize() + 2 * decorationMargin() + 2 * border(), + decorationSize() + 2 * decorationMargin() + 1 * border()); } QRect KisNodeViewColorScheme::relExpandButtonRect() const { const int newY = rowHeight() - decorationMargin() - decorationSize(); QRect rc = relDecorationRect(); rc.moveTop(newY); return rc; } QColor KisNodeViewColorScheme::colorLabel(int index) const { /** * We should ensure that the index of the overflowing range * will never be zero again. */ if (index >= m_d->colorLabels.size()) { index = 1 + index % (m_d->colorLabels.size() - 1); } else { index = index % m_d->colorLabels.size(); } return m_d->colorLabels[index]; } QVector KisNodeViewColorScheme::allColorLabels() const { return m_d->colorLabels; } diff --git a/libs/ui/kis_node_view_color_scheme.h b/libs/ui/kis_node_view_color_scheme.h index ef96293a47..afb1de6945 100644 --- a/libs/ui/kis_node_view_color_scheme.h +++ b/libs/ui/kis_node_view_color_scheme.h @@ -1,73 +1,74 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 __KIS_NODE_VIEW_COLOR_SCHEME_H #define __KIS_NODE_VIEW_COLOR_SCHEME_H #include #include #include "kritaui_export.h" class QTreeView; class QStyleOptionViewItem; class QRect; class KRITAUI_EXPORT KisNodeViewColorScheme { public: KisNodeViewColorScheme(); ~KisNodeViewColorScheme(); static KisNodeViewColorScheme* instance(); QColor gridColor(const QStyleOptionViewItem &option, QTreeView *view); int visibilitySize() const; int visibilityMargin() const; int thumbnailSize() const; int thumbnailMargin() const; int decorationSize() const; int decorationMargin() const; int textMargin() const; int iconSize() const; int iconMargin() const; int border() const; int rowHeight() const; int visibilityColumnWidth() const; int indentation() const; + QRect relVisibilityRect() const; QRect relThumbnailRect() const; QRect relDecorationRect() const; QRect relExpandButtonRect() const; QColor colorLabel(int index) const; QVector allColorLabels() const; private: struct Private; const QScopedPointer m_d; }; #endif /* __KIS_NODE_VIEW_COLOR_SCHEME_H */ diff --git a/libs/ui/kis_painting_assistants_decoration.cpp b/libs/ui/kis_painting_assistants_decoration.cpp index de5fe80866..a782900435 100644 --- a/libs/ui/kis_painting_assistants_decoration.cpp +++ b/libs/ui/kis_painting_assistants_decoration.cpp @@ -1,484 +1,490 @@ /* * Copyright (c) 2009 Cyrille Berger * Copyright (c) 2017 Scott Petrovic * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 "kis_painting_assistants_decoration.h" #include #include #include #include #include #include #include "kis_debug.h" #include "KisDocument.h" #include "kis_canvas2.h" #include "kis_icon_utils.h" #include "KisViewManager.h" #include #include struct KisPaintingAssistantsDecoration::Private { Private() : assistantVisible(false) , outlineVisible(false) , snapOnlyOneAssistant(true) , firstAssistant(0) , aFirstStroke(false) , m_handleSize(14) {} bool assistantVisible; bool outlineVisible; bool snapOnlyOneAssistant; KisPaintingAssistantSP firstAssistant; KisPaintingAssistantSP selectedAssistant; bool aFirstStroke; bool m_isEditingAssistants = false; bool m_outlineVisible = false; int m_handleSize; // size of editor handles on assistants // move, visibility, delete icons for each assistant. These only display while the assistant tool is active // these icons will be covered by the kis_paintint_assistant_decoration with things like the perspective assistant AssistantEditorData toolData; QPixmap m_iconDelete = KisIconUtils::loadIcon("dialog-cancel").pixmap(toolData.deleteIconSize, toolData.deleteIconSize); QPixmap m_iconSnapOn = KisIconUtils::loadIcon("visible").pixmap(toolData.snapIconSize, toolData.snapIconSize); QPixmap m_iconSnapOff = KisIconUtils::loadIcon("novisible").pixmap(toolData.snapIconSize, toolData.snapIconSize); QPixmap m_iconMove = KisIconUtils::loadIcon("transform-move").pixmap(toolData.moveIconSize, toolData.moveIconSize); KisCanvas2 * m_canvas = 0; }; KisPaintingAssistantsDecoration::KisPaintingAssistantsDecoration(QPointer parent) : KisCanvasDecoration("paintingAssistantsDecoration", parent), d(new Private) { setAssistantVisible(true); setOutlineVisible(true); setPriority(95); d->snapOnlyOneAssistant = true; //turn on by default. } KisPaintingAssistantsDecoration::~KisPaintingAssistantsDecoration() { delete d; } void KisPaintingAssistantsDecoration::addAssistant(KisPaintingAssistantSP assistant) { QList assistants = view()->document()->assistants(); if (assistants.contains(assistant)) return; assistants.append(assistant); assistant->setAssistantGlobalColorCache(view()->document()->assistantsGlobalColor()); view()->document()->setAssistants(assistants); setVisible(!assistants.isEmpty()); emit assistantChanged(); } void KisPaintingAssistantsDecoration::removeAssistant(KisPaintingAssistantSP assistant) { QList assistants = view()->document()->assistants(); KIS_ASSERT_RECOVER_NOOP(assistants.contains(assistant)); if (assistants.removeAll(assistant)) { view()->document()->setAssistants(assistants); setVisible(!assistants.isEmpty()); emit assistantChanged(); } } void KisPaintingAssistantsDecoration::removeAll() { QList assistants = view()->document()->assistants(); assistants.clear(); view()->document()->setAssistants(assistants); setVisible(!assistants.isEmpty()); emit assistantChanged(); } QPointF KisPaintingAssistantsDecoration::adjustPosition(const QPointF& point, const QPointF& strokeBegin) { if (assistants().empty()) { return point; } if (assistants().count() == 1) { if(assistants().first()->isSnappingActive() == true){ QPointF newpoint = assistants().first()->adjustPosition(point, strokeBegin); // check for NaN if (newpoint.x() != newpoint.x()) return point; return newpoint; } } QPointF best = point; double distance = DBL_MAX; //the following tries to find the closest point to stroke-begin. It checks all assistants for the closest point// if(!d->snapOnlyOneAssistant){ Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) { if(assistant->isSnappingActive() == true){//this checks if the assistant in question has it's snapping boolean turned on// QPointF pt = assistant->adjustPosition(point, strokeBegin); if (pt.x() != pt.x()) continue; double dist = qAbs(pt.x() - point.x()) + qAbs(pt.y() - point.y()); if (dist < distance) { best = pt; distance = dist; } } } } else if (d->aFirstStroke==false) { Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) { if(assistant->isSnappingActive() == true){//this checks if the assistant in question has it's snapping boolean turned on// QPointF pt = assistant->adjustPosition(point, strokeBegin); if (pt.x() != pt.x()) continue; double dist = qAbs(pt.x() - point.x()) + qAbs(pt.y() - point.y()); if (dist < distance) { best = pt; distance = dist; d->firstAssistant = assistant; } } } } else if(d->firstAssistant) { //make sure there's a first assistant to begin with.// - best = d->firstAssistant->adjustPosition(point, strokeBegin); + QPointF newpoint = d->firstAssistant->adjustPosition(point, strokeBegin); + // BUGFIX: 402535 + // assistants might return (NaN,NaN), must always check for that + if (newpoint.x() == newpoint.x()) { + // not a NaN + best = newpoint; + } } else { d->aFirstStroke=false; } //this is here to be compatible with the movement in the perspective tool. qreal dx = point.x() - strokeBegin.x(), dy = point.y() - strokeBegin.y(); if (dx * dx + dy * dy >= 4.0) { // allow some movement before snapping d->aFirstStroke=true; } return best; } void KisPaintingAssistantsDecoration::endStroke() { d->aFirstStroke = false; Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) { assistant->endStroke(); } } void KisPaintingAssistantsDecoration::drawDecoration(QPainter& gc, const QRectF& updateRect, const KisCoordinatesConverter *converter,KisCanvas2* canvas) { if(assistants().length() == 0) { return; // no assistants to worry about, ok to exit } if (!canvas) { dbgFile<<"canvas does not exist in painting assistant decoration, you may have passed arguments incorrectly:"<m_canvas = canvas; } // the preview functionality for assistants. do not show while editing if (d->m_isEditingAssistants) { d->m_outlineVisible = false; } else { d->m_outlineVisible = outlineVisibility(); } Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) { assistant->drawAssistant(gc, updateRect, converter, true, canvas, assistantVisibility(), d->m_outlineVisible); if (isEditingAssistants()) { drawHandles(assistant, gc, converter); } } // draw editor controls on top of all assistant lines (why this code is last) if (isEditingAssistants()) { Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) { drawEditorWidget(assistant, gc, converter); } } } void KisPaintingAssistantsDecoration::drawHandles(KisPaintingAssistantSP assistant, QPainter& gc, const KisCoordinatesConverter *converter) { QTransform initialTransform = converter->documentToWidgetTransform(); QColor colorToPaint = assistant->effectiveAssistantColor(); Q_FOREACH (const KisPaintingAssistantHandleSP handle, assistant->handles()) { QPointF transformedHandle = initialTransform.map(*handle); QRectF ellipse(transformedHandle - QPointF(handleSize() * 0.5, handleSize() * 0.5), QSizeF(handleSize(), handleSize())); QPainterPath path; path.addEllipse(ellipse); gc.save(); gc.setPen(Qt::NoPen); gc.setBrush(colorToPaint); gc.drawPath(path); gc.restore(); } // some assistants have side handles like the vanishing point assistant Q_FOREACH (const KisPaintingAssistantHandleSP handle, assistant->sideHandles()) { QPointF transformedHandle = initialTransform.map(*handle); QRectF ellipse(transformedHandle - QPointF(handleSize() * 0.5, handleSize() * 0.5), QSizeF(handleSize(), handleSize())); QPainterPath path; path.addEllipse(ellipse); gc.save(); gc.setPen(Qt::NoPen); gc.setBrush(colorToPaint); gc.drawPath(path); gc.restore(); } } int KisPaintingAssistantsDecoration::handleSize() { return d->m_handleSize; } void KisPaintingAssistantsDecoration::setHandleSize(int handleSize) { d->m_handleSize = handleSize; } QList KisPaintingAssistantsDecoration::handles() { QList hs; Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) { Q_FOREACH (const KisPaintingAssistantHandleSP handle, assistant->handles()) { if (!hs.contains(handle)) { hs.push_back(handle); } } Q_FOREACH (const KisPaintingAssistantHandleSP handle, assistant->sideHandles()) { if (!hs.contains(handle)) { hs.push_back(handle); } } } return hs; } QList KisPaintingAssistantsDecoration::assistants() const { QList assistants = view()->document()->assistants(); return assistants; } KisPaintingAssistantSP KisPaintingAssistantsDecoration::selectedAssistant() { return d->selectedAssistant; } void KisPaintingAssistantsDecoration::setSelectedAssistant(KisPaintingAssistantSP assistant) { d->selectedAssistant = assistant; emit selectedAssistantChanged(); } void KisPaintingAssistantsDecoration::deselectAssistant() { d->selectedAssistant.clear(); } void KisPaintingAssistantsDecoration::setAssistantVisible(bool set) { d->assistantVisible=set; } void KisPaintingAssistantsDecoration::setOutlineVisible(bool set) { d->outlineVisible=set; } void KisPaintingAssistantsDecoration::setOnlyOneAssistantSnap(bool assistant) { d->snapOnlyOneAssistant = assistant; } bool KisPaintingAssistantsDecoration::assistantVisibility() { return d->assistantVisible; } bool KisPaintingAssistantsDecoration::outlineVisibility() { return d->outlineVisible; } void KisPaintingAssistantsDecoration::uncache() { Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) { assistant->uncache(); } } void KisPaintingAssistantsDecoration::toggleAssistantVisible() { setAssistantVisible(!assistantVisibility()); uncache(); } void KisPaintingAssistantsDecoration::toggleOutlineVisible() { setOutlineVisible(!outlineVisibility()); } QColor KisPaintingAssistantsDecoration::globalAssistantsColor() { return view()->document()->assistantsGlobalColor(); } void KisPaintingAssistantsDecoration::setGlobalAssistantsColor(QColor color) { // view()->document() is referenced multiple times in this class // it is used to later store things in the KRA file when saving. view()->document()->setAssistantsGlobalColor(color); Q_FOREACH (KisPaintingAssistantSP assistant, assistants()) { assistant->setAssistantGlobalColorCache(color); } uncache(); } void KisPaintingAssistantsDecoration::activateAssistantsEditor() { setVisible(true); // this turns on the decorations in general. we leave it on at this point d->m_isEditingAssistants = true; uncache(); // updates visuals when editing } void KisPaintingAssistantsDecoration::deactivateAssistantsEditor() { if (!d->m_canvas) { return; } d->m_isEditingAssistants = false; // some elements are hidden when we aren't editing uncache(); // updates visuals when not editing } bool KisPaintingAssistantsDecoration::isEditingAssistants() { return d->m_isEditingAssistants; } QPointF KisPaintingAssistantsDecoration::snapToGuide(KoPointerEvent *e, const QPointF &offset, bool useModifiers) { if (!d->m_canvas || !d->m_canvas->currentImage()) { return e->point; } KoSnapGuide *snapGuide = d->m_canvas->snapGuide(); QPointF pos = snapGuide->snap(e->point, offset, useModifiers ? e->modifiers() : Qt::NoModifier); return pos; } QPointF KisPaintingAssistantsDecoration::snapToGuide(const QPointF& pt, const QPointF &offset) { if (!d->m_canvas) { return pt; } KoSnapGuide *snapGuide = d->m_canvas->snapGuide(); QPointF pos = snapGuide->snap(pt, offset, Qt::NoModifier); return pos; } /* * functions only used internally in this class * we potentially could make some of these inline to speed up performance */ void KisPaintingAssistantsDecoration::drawEditorWidget(KisPaintingAssistantSP assistant, QPainter& gc, const KisCoordinatesConverter *converter) { if (!assistant->isAssistantComplete()) { return; } QTransform initialTransform = converter->documentToWidgetTransform(); // We are going to put all of the assistant actions below the bounds of the assistant // so they are out of the way // assistant->buttonPosition() gets the center X/Y position point QPointF actionsPosition = initialTransform.map(assistant->buttonPosition()); AssistantEditorData toolData; // shared const data for positioning and sizing QPointF iconMovePosition(actionsPosition + toolData.moveIconPosition); QPointF iconSnapPosition(actionsPosition + toolData.snapIconPosition); QPointF iconDeletePosition(actionsPosition + toolData.deleteIconPosition); // Background container for helpers QBrush backgroundColor = d->m_canvas->viewManager()->mainWindow()->palette().window(); QPointF actionsBGRectangle(actionsPosition + QPointF(10, 10)); gc.setRenderHint(QPainter::Antialiasing); QPainterPath bgPath; bgPath.addRoundedRect(QRectF(actionsBGRectangle.x(), actionsBGRectangle.y(), 110, 40), 6, 6); QPen stroke(QColor(60, 60, 60, 80), 2); // if the assistant is selected, make outline stroke fatter and use theme's highlight color // for better visual feedback if (selectedAssistant()) { // there might not be a selected assistant, so do not seg fault if (assistant->buttonPosition() == selectedAssistant()->buttonPosition()) { stroke.setWidth(4); stroke.setColor(qApp->palette().color(QPalette::Highlight)); } } // draw the final result gc.setPen(stroke); gc.fillPath(bgPath, backgroundColor); gc.drawPath(bgPath); // Move Assistant Tool helper gc.drawPixmap(iconMovePosition, d->m_iconMove); // active toggle if (assistant->isSnappingActive() == true) { gc.drawPixmap(iconSnapPosition, d->m_iconSnapOn); } else { gc.drawPixmap(iconSnapPosition, d->m_iconSnapOff); } gc.drawPixmap(iconDeletePosition, d->m_iconDelete); } diff --git a/libs/ui/kis_paintop_box.cc b/libs/ui/kis_paintop_box.cc index 793b2f607c..e1fe23c322 100644 --- a/libs/ui/kis_paintop_box.cc +++ b/libs/ui/kis_paintop_box.cc @@ -1,1349 +1,1351 @@ /* * kis_paintop_box.cc - part of KImageShop/Krayon/Krita * * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) * Copyright (c) 2009-2011 Sven Langkamp (sven.langkamp@gmail.com) * Copyright (c) 2010 Lukáš Tvrdý * Copyright (C) 2011 Silvio Heinrich * Copyright (C) 2011 Srikanth Tiyyagura * Copyright (c) 2014 Mohit Goyal * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 "kis_paintop_box.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 #include #include #include "kis_canvas2.h" #include "kis_node_manager.h" #include "KisViewManager.h" #include "kis_canvas_resource_provider.h" #include "KisResourceServerProvider.h" #include "kis_favorite_resource_manager.h" #include "kis_config.h" #include "kis_popup_button.h" #include "widgets/kis_iconwidget.h" #include "widgets/kis_tool_options_popup.h" #include "widgets/kis_paintop_presets_popup.h" #include "widgets/kis_paintop_presets_chooser_popup.h" #include "widgets/kis_workspace_chooser.h" #include "widgets/kis_paintop_list_widget.h" #include "widgets/kis_slider_spin_box.h" #include "widgets/kis_cmb_composite.h" #include "widgets/kis_widget_chooser.h" #include "tool/kis_tool.h" #include "kis_signals_blocker.h" #include "kis_action_manager.h" #include "kis_highlighted_button.h" KisPaintopBox::KisPaintopBox(KisViewManager *view, QWidget *parent, const char *name) : QWidget(parent) , m_resourceProvider(view->resourceProvider()) , m_optionWidget(0) , m_toolOptionsPopupButton(0) , m_brushEditorPopupButton(0) , m_presetSelectorPopupButton(0) , m_toolOptionsPopup(0) , m_viewManager(view) , m_previousNode(0) , m_currTabletToolID(KoInputDevice::invalid()) , m_presetsEnabled(true) , m_blockUpdate(false) , m_dirtyPresetsEnabled(false) , m_eraserBrushSizeEnabled(false) , m_eraserBrushOpacityEnabled(false) { Q_ASSERT(view != 0); setObjectName(name); KisConfig cfg(true); m_dirtyPresetsEnabled = cfg.useDirtyPresets(); m_eraserBrushSizeEnabled = cfg.useEraserBrushSize(); m_eraserBrushOpacityEnabled = cfg.useEraserBrushOpacity(); KAcceleratorManager::setNoAccel(this); setWindowTitle(i18n("Painter's Toolchest")); m_favoriteResourceManager = new KisFavoriteResourceManager(this); KConfigGroup grp = KSharedConfig::openConfig()->group("krita").group("Toolbar BrushesAndStuff"); int iconsize = grp.readEntry("IconSize", 32); if (!cfg.toolOptionsInDocker()) { m_toolOptionsPopupButton = new KisPopupButton(this); m_toolOptionsPopupButton->setIcon(KisIconUtils::loadIcon("configure")); m_toolOptionsPopupButton->setToolTip(i18n("Tool Settings")); m_toolOptionsPopupButton->setFixedSize(iconsize, iconsize); } m_brushEditorPopupButton = new KisIconWidget(this); m_brushEditorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_02")); m_brushEditorPopupButton->setToolTip(i18n("Edit brush settings")); m_brushEditorPopupButton->setFixedSize(iconsize, iconsize); m_presetSelectorPopupButton = new KisPopupButton(this); m_presetSelectorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_01")); m_presetSelectorPopupButton->setToolTip(i18n("Choose brush preset")); m_presetSelectorPopupButton->setFixedSize(iconsize, iconsize); m_eraseModeButton = new KisHighlightedToolButton(this); m_eraseModeButton->setFixedSize(iconsize, iconsize); m_eraseModeButton->setCheckable(true); m_eraseAction = m_viewManager->actionManager()->createAction("erase_action"); m_eraseModeButton->setDefaultAction(m_eraseAction); m_reloadButton = new QToolButton(this); m_reloadButton->setFixedSize(iconsize, iconsize); m_reloadAction = m_viewManager->actionManager()->createAction("reload_preset_action"); m_reloadButton->setDefaultAction(m_reloadAction); m_alphaLockButton = new KisHighlightedToolButton(this); m_alphaLockButton->setFixedSize(iconsize, iconsize); m_alphaLockButton->setCheckable(true); KisAction* alphaLockAction = m_viewManager->actionManager()->createAction("preserve_alpha"); m_alphaLockButton->setDefaultAction(alphaLockAction); // horizontal and vertical mirror toolbar buttons // mirror tool options for the X Mirror QMenu *toolbarMenuXMirror = new QMenu(); hideCanvasDecorationsX = m_viewManager->actionManager()->createAction("mirrorX-hideDecorations"); toolbarMenuXMirror->addAction(hideCanvasDecorationsX); lockActionX = m_viewManager->actionManager()->createAction("mirrorX-lock"); toolbarMenuXMirror->addAction(lockActionX); moveToCenterActionX = m_viewManager->actionManager()->createAction("mirrorX-moveToCenter"); toolbarMenuXMirror->addAction(moveToCenterActionX); // mirror tool options for the Y Mirror QMenu *toolbarMenuYMirror = new QMenu(); hideCanvasDecorationsY = m_viewManager->actionManager()->createAction("mirrorY-hideDecorations"); toolbarMenuYMirror->addAction(hideCanvasDecorationsY); lockActionY = m_viewManager->actionManager()->createAction("mirrorY-lock"); toolbarMenuYMirror->addAction(lockActionY); moveToCenterActionY = m_viewManager->actionManager()->createAction("mirrorY-moveToCenter"); toolbarMenuYMirror->addAction(moveToCenterActionY); // create horizontal and vertical mirror buttons m_hMirrorButton = new KisHighlightedToolButton(this); int menuPadding = 10; m_hMirrorButton->setFixedSize(iconsize + menuPadding, iconsize); m_hMirrorButton->setCheckable(true); m_hMirrorAction = m_viewManager->actionManager()->createAction("hmirror_action"); m_hMirrorButton->setDefaultAction(m_hMirrorAction); m_hMirrorButton->setMenu(toolbarMenuXMirror); m_hMirrorButton->setPopupMode(QToolButton::MenuButtonPopup); m_vMirrorButton = new KisHighlightedToolButton(this); m_vMirrorButton->setFixedSize(iconsize + menuPadding, iconsize); m_vMirrorButton->setCheckable(true); m_vMirrorAction = m_viewManager->actionManager()->createAction("vmirror_action"); m_vMirrorButton->setDefaultAction(m_vMirrorAction); m_vMirrorButton->setMenu(toolbarMenuYMirror); m_vMirrorButton->setPopupMode(QToolButton::MenuButtonPopup); // add connections for horizontal and mirrror buttons connect(lockActionX, SIGNAL(toggled(bool)), this, SLOT(slotLockXMirrorToggle(bool))); connect(lockActionY, SIGNAL(toggled(bool)), this, SLOT(slotLockYMirrorToggle(bool))); connect(moveToCenterActionX, SIGNAL(triggered(bool)), this, SLOT(slotMoveToCenterMirrorX())); connect(moveToCenterActionY, SIGNAL(triggered(bool)), this, SLOT(slotMoveToCenterMirrorY())); connect(hideCanvasDecorationsX, SIGNAL(toggled(bool)), this, SLOT(slotHideDecorationMirrorX(bool))); connect(hideCanvasDecorationsY, SIGNAL(toggled(bool)), this, SLOT(slotHideDecorationMirrorY(bool))); const bool sliderLabels = cfg.sliderLabels(); int sliderWidth; if (sliderLabels) { sliderWidth = 150 * logicalDpiX() / 96; } else { sliderWidth = 120 * logicalDpiX() / 96; } for (int i = 0; i < 3; ++i) { m_sliderChooser[i] = new KisWidgetChooser(i + 1); KisDoubleSliderSpinBox* slOpacity; KisDoubleSliderSpinBox* slFlow; KisDoubleSliderSpinBox* slSize; if (sliderLabels) { slOpacity = m_sliderChooser[i]->addWidget("opacity"); slFlow = m_sliderChooser[i]->addWidget("flow"); slSize = m_sliderChooser[i]->addWidget("size"); slOpacity->setPrefix(QString("%1 ").arg(i18n("Opacity:"))); slFlow->setPrefix(QString("%1 ").arg(i18n("Flow:"))); slSize->setPrefix(QString("%1 ").arg(i18n("Size:"))); } else { slOpacity = m_sliderChooser[i]->addWidget("opacity", i18n("Opacity:")); slFlow = m_sliderChooser[i]->addWidget("flow", i18n("Flow:")); slSize = m_sliderChooser[i]->addWidget("size", i18n("Size:")); } slOpacity->setRange(0, 100, 0); slOpacity->setValue(100); slOpacity->setSingleStep(5); slOpacity->setSuffix("%"); slOpacity->setMinimumWidth(qMax(sliderWidth, slOpacity->sizeHint().width())); slOpacity->setFixedHeight(iconsize); slOpacity->setBlockUpdateSignalOnDrag(true); slFlow->setRange(0, 100, 0); slFlow->setValue(100); slFlow->setSingleStep(5); slFlow->setSuffix("%"); slFlow->setMinimumWidth(qMax(sliderWidth, slFlow->sizeHint().width())); slFlow->setFixedHeight(iconsize); slFlow->setBlockUpdateSignalOnDrag(true); slSize->setRange(0, cfg.readEntry("maximumBrushSize", 1000), 2); slSize->setValue(100); slSize->setSingleStep(1); slSize->setExponentRatio(3.0); slSize->setSuffix(i18n(" px")); slSize->setMinimumWidth(qMax(sliderWidth, slSize->sizeHint().width())); slSize->setFixedHeight(iconsize); slSize->setBlockUpdateSignalOnDrag(true); m_sliderChooser[i]->chooseWidget(cfg.toolbarSlider(i + 1)); } m_cmbCompositeOp = new KisCompositeOpComboBox(); m_cmbCompositeOp->setFixedHeight(iconsize); Q_FOREACH (KisAction * a, m_cmbCompositeOp->blendmodeActions()) { m_viewManager->actionManager()->addAction(a->text(), a); } m_workspaceWidget = new KisPopupButton(this); m_workspaceWidget->setIcon(KisIconUtils::loadIcon("view-choose")); m_workspaceWidget->setToolTip(i18n("Choose workspace")); m_workspaceWidget->setFixedSize(iconsize, iconsize); m_workspaceWidget->setPopupWidget(new KisWorkspaceChooser(view)); QHBoxLayout* baseLayout = new QHBoxLayout(this); m_paintopWidget = new QWidget(this); baseLayout->addWidget(m_paintopWidget); baseLayout->setSpacing(4); baseLayout->setContentsMargins(0, 0, 0, 0); m_layout = new QHBoxLayout(m_paintopWidget); if (!cfg.toolOptionsInDocker()) { m_layout->addWidget(m_toolOptionsPopupButton); } m_layout->addWidget(m_brushEditorPopupButton); m_layout->addWidget(m_presetSelectorPopupButton); m_layout->setSpacing(4); m_layout->setContentsMargins(0, 0, 0, 0); QWidget* compositeActions = new QWidget(this); QHBoxLayout* compositeLayout = new QHBoxLayout(compositeActions); compositeLayout->addWidget(m_cmbCompositeOp); compositeLayout->addWidget(m_eraseModeButton); compositeLayout->addWidget(m_alphaLockButton); compositeLayout->setSpacing(4); compositeLayout->setContentsMargins(0, 0, 0, 0); compositeLayout->addWidget(m_reloadButton); QWidgetAction * action; action = new QWidgetAction(this); view->actionCollection()->addAction("composite_actions", action); action->setText(i18n("Brush composite")); action->setDefaultWidget(compositeActions); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("brushslider1", action); view->actionCollection()->addAction("brushslider1", action); action->setDefaultWidget(m_sliderChooser[0]); connect(action, SIGNAL(triggered()), m_sliderChooser[0], SLOT(showPopupWidget())); connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_sliderChooser[0], SLOT(updateThemedIcons())); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("brushslider2", action); view->actionCollection()->addAction("brushslider2", action); action->setDefaultWidget(m_sliderChooser[1]); connect(action, SIGNAL(triggered()), m_sliderChooser[1], SLOT(showPopupWidget())); connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_sliderChooser[1], SLOT(updateThemedIcons())); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("brushslider3", action); view->actionCollection()->addAction("brushslider3", action); action->setDefaultWidget(m_sliderChooser[2]); connect(action, SIGNAL(triggered()), m_sliderChooser[2], SLOT(showPopupWidget())); connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_sliderChooser[2], SLOT(updateThemedIcons())); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("next_favorite_preset", action); view->actionCollection()->addAction("next_favorite_preset", action); connect(action, SIGNAL(triggered()), this, SLOT(slotNextFavoritePreset())); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("previous_favorite_preset", action); view->actionCollection()->addAction("previous_favorite_preset", action); connect(action, SIGNAL(triggered()), this, SLOT(slotPreviousFavoritePreset())); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("previous_preset", action); view->actionCollection()->addAction("previous_preset", action); connect(action, SIGNAL(triggered()), this, SLOT(slotSwitchToPreviousPreset())); if (!cfg.toolOptionsInDocker()) { action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("show_tool_options", action); view->actionCollection()->addAction("show_tool_options", action); connect(action, SIGNAL(triggered()), m_toolOptionsPopupButton, SLOT(showPopupWidget())); } action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("show_brush_editor", action); view->actionCollection()->addAction("show_brush_editor", action); connect(action, SIGNAL(triggered()), m_brushEditorPopupButton, SLOT(showPopupWidget())); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("show_brush_presets", action); view->actionCollection()->addAction("show_brush_presets", action); connect(action, SIGNAL(triggered()), m_presetSelectorPopupButton, SLOT(showPopupWidget())); QWidget* mirrorActions = new QWidget(this); QHBoxLayout* mirrorLayout = new QHBoxLayout(mirrorActions); mirrorLayout->addWidget(m_hMirrorButton); mirrorLayout->addWidget(m_vMirrorButton); mirrorLayout->setSpacing(4); mirrorLayout->setContentsMargins(0, 0, 0, 0); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("mirror_actions", action); action->setDefaultWidget(mirrorActions); view->actionCollection()->addAction("mirror_actions", action); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("workspaces", action); view->actionCollection()->addAction("workspaces", action); action->setDefaultWidget(m_workspaceWidget); if (!cfg.toolOptionsInDocker()) { m_toolOptionsPopup = new KisToolOptionsPopup(); m_toolOptionsPopupButton->setPopupWidget(m_toolOptionsPopup); m_toolOptionsPopup->switchDetached(false); } m_savePresetWidget = new KisPresetSaveWidget(this); m_presetsPopup = new KisPaintOpPresetsPopup(m_resourceProvider, m_favoriteResourceManager, m_savePresetWidget); m_brushEditorPopupButton->setPopupWidget(m_presetsPopup); m_presetsPopup->parentWidget()->setWindowTitle(i18n("Brush Editor")); connect(m_presetsPopup, SIGNAL(brushEditorShown()), SLOT(slotUpdateOptionsWidgetPopup())); connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_presetsPopup, SLOT(updateThemedIcons())); m_presetsChooserPopup = new KisPaintOpPresetsChooserPopup(); m_presetsChooserPopup->setMinimumHeight(550); m_presetsChooserPopup->setMinimumWidth(450); m_presetSelectorPopupButton->setPopupWidget(m_presetsChooserPopup); m_currCompositeOpID = KoCompositeOpRegistry::instance().getDefaultCompositeOp().id(); slotNodeChanged(view->activeNode()); // Get all the paintops QList keys = KisPaintOpRegistry::instance()->keys(); QList factoryList; Q_FOREACH (const QString & paintopId, keys) { factoryList.append(KisPaintOpRegistry::instance()->get(paintopId)); } m_presetsPopup->setPaintOpList(factoryList); connect(m_presetsPopup , SIGNAL(paintopActivated(QString)) , SLOT(slotSetPaintop(QString))); connect(m_presetsPopup , SIGNAL(defaultPresetClicked()) , SLOT(slotSetupDefaultPreset())); connect(m_presetsPopup , SIGNAL(signalResourceSelected(KoResourceSP )), SLOT(resourceSelected(KoResourceSP ))); connect(m_presetsPopup , SIGNAL(reloadPresetClicked()) , SLOT(slotReloadPreset())); connect(m_presetsPopup , SIGNAL(dirtyPresetToggled(bool)) , SLOT(slotDirtyPresetToggled(bool))); connect(m_presetsPopup , SIGNAL(eraserBrushSizeToggled(bool)) , SLOT(slotEraserBrushSizeToggled(bool))); connect(m_presetsPopup , SIGNAL(eraserBrushOpacityToggled(bool)) , SLOT(slotEraserBrushOpacityToggled(bool))); connect(m_presetsPopup, SIGNAL(createPresetFromScratch(QString)), this, SLOT(slotCreatePresetFromScratch(QString))); connect(m_presetsChooserPopup, SIGNAL(resourceSelected(KoResourceSP )) , SLOT(resourceSelected(KoResourceSP ))); connect(m_presetsChooserPopup, SIGNAL(resourceClicked(KoResourceSP )) , SLOT(resourceSelected(KoResourceSP ))); connect(m_resourceProvider , SIGNAL(sigNodeChanged(KisNodeSP)) , SLOT(slotNodeChanged(KisNodeSP))); connect(m_cmbCompositeOp , SIGNAL(currentIndexChanged(int)) , SLOT(slotSetCompositeMode(int))); connect(m_eraseAction , SIGNAL(toggled(bool)) , SLOT(slotToggleEraseMode(bool))); connect(alphaLockAction , SIGNAL(toggled(bool)) , SLOT(slotToggleAlphaLockMode(bool))); m_disablePressureAction = m_viewManager->actionManager()->createAction("disable_pressure"); connect(m_disablePressureAction , SIGNAL(toggled(bool)) , SLOT(slotDisablePressureMode(bool))); m_disablePressureAction->setChecked(true); connect(m_hMirrorAction , SIGNAL(toggled(bool)) , SLOT(slotHorizontalMirrorChanged(bool))); connect(m_vMirrorAction , SIGNAL(toggled(bool)) , SLOT(slotVerticalMirrorChanged(bool))); connect(m_reloadAction , SIGNAL(triggered()) , SLOT(slotReloadPreset())); connect(m_sliderChooser[0]->getWidget("opacity"), SIGNAL(valueChanged(qreal)), SLOT(slotSlider1Changed())); connect(m_sliderChooser[0]->getWidget("flow") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider1Changed())); connect(m_sliderChooser[0]->getWidget("size") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider1Changed())); connect(m_sliderChooser[1]->getWidget("opacity"), SIGNAL(valueChanged(qreal)), SLOT(slotSlider2Changed())); connect(m_sliderChooser[1]->getWidget("flow") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider2Changed())); connect(m_sliderChooser[1]->getWidget("size") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider2Changed())); connect(m_sliderChooser[2]->getWidget("opacity"), SIGNAL(valueChanged(qreal)), SLOT(slotSlider3Changed())); connect(m_sliderChooser[2]->getWidget("flow") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider3Changed())); connect(m_sliderChooser[2]->getWidget("size") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider3Changed())); //Needed to connect canvas to favorite resource manager connect(m_viewManager->resourceProvider(), SIGNAL(sigFGColorChanged(KoColor)), SLOT(slotUnsetEraseMode())); connect(m_resourceProvider, SIGNAL(sigFGColorUsed(KoColor)), m_favoriteResourceManager, SLOT(slotAddRecentColor(KoColor))); connect(m_resourceProvider, SIGNAL(sigFGColorChanged(KoColor)), m_favoriteResourceManager, SLOT(slotChangeFGColorSelector(KoColor))); connect(m_resourceProvider, SIGNAL(sigBGColorChanged(KoColor)), m_favoriteResourceManager, SLOT(slotSetBGColor(KoColor))); // cold initialization m_favoriteResourceManager->slotChangeFGColorSelector(m_resourceProvider->fgColor()); m_favoriteResourceManager->slotSetBGColor(m_resourceProvider->bgColor()); connect(m_favoriteResourceManager, SIGNAL(sigSetFGColor(KoColor)), m_resourceProvider, SLOT(slotSetFGColor(KoColor))); connect(m_favoriteResourceManager, SIGNAL(sigSetBGColor(KoColor)), m_resourceProvider, SLOT(slotSetBGColor(KoColor))); connect(m_favoriteResourceManager, SIGNAL(sigEnableChangeColor(bool)), m_resourceProvider, SLOT(slotResetEnableFGChange(bool))); connect(view->mainWindow(), SIGNAL(themeChanged()), this, SLOT(slotUpdateSelectionIcon())); connect(m_resourceProvider->resourceManager(), SIGNAL(canvasResourceChanged(int,QVariant)), this, SLOT(slotCanvasResourceChanged(int,QVariant))); slotInputDeviceChanged(KoToolManager::instance()->currentInputDevice()); KisPaintOpPresetResourceServer *rserver = KisResourceServerProvider::instance()->paintOpPresetServer(); m_eraserName = "eraser_circle"; m_defaultPresetName = "basic_tip_default"; bool foundEraser = false; bool foundTip = false; for (int i = 0; i < rserver->resourceCount(); i++) { KisPaintOpPresetSP resource = rserver->resources()[i]; if (resource->name().toLower().contains("eraser_circle")) { m_eraserName = resource->name(); foundEraser = true; } else if (foundEraser == false && (resource->name().toLower().contains("eraser") || resource->filename().toLower().contains("eraser"))) { m_eraserName = resource->name(); foundEraser = true; } if (resource->name().toLower().contains("basic_tip_default")) { m_defaultPresetName = resource->name(); foundTip = true; } else if (foundTip == false && (resource->name().toLower().contains("default") || resource->filename().toLower().contains("default"))) { m_defaultPresetName = resource->name(); foundTip = true; } } } KisPaintopBox::~KisPaintopBox() { KisConfig cfg(false); QMapIterator iter(m_tabletToolMap); while (iter.hasNext()) { iter.next(); //qDebug() << "Writing last used preset for" << iter.key().pointer << iter.key().uniqueID << iter.value().preset->name(); if ((iter.key().pointer) == QTabletEvent::Eraser) { cfg.writeEntry(QString("LastEraser_%1").arg(iter.key().uniqueID) , iter.value().preset->name()); } else { cfg.writeEntry(QString("LastPreset_%1").arg(iter.key().uniqueID) , iter.value().preset->name()); } } // Do not delete the widget, since it is global to the application, not owned by the view m_presetsPopup->setPaintOpSettingsWidget(0); qDeleteAll(m_paintopOptionWidgets); delete m_favoriteResourceManager; for (int i = 0; i < 3; ++i) { delete m_sliderChooser[i]; } } void KisPaintopBox::restoreResource(KoResourceSP resource) { KisPaintOpPresetSP preset = resource.dynamicCast(); if (preset) { setCurrentPaintop(preset); m_presetsPopup->setPresetImage(preset->image()); m_presetsPopup->resourceSelected(resource); } } void KisPaintopBox::newOptionWidgets(const QList > &optionWidgetList) { if (m_toolOptionsPopup) { m_toolOptionsPopup->newOptionWidgets(optionWidgetList); } } void KisPaintopBox::resourceSelected(KoResourceSP resource) { + KIS_SAFE_ASSERT_RECOVER_RETURN(m_optionWidget); + m_presetsPopup->setCreatingBrushFromScratch(false); // show normal UI elements when we are not creating KisPaintOpPresetSP preset = resource.dynamicCast(); if (preset && preset != m_resourceProvider->currentPreset()) { if (!preset->settings()->isLoadable()) return; if (!m_dirtyPresetsEnabled) { KisSignalsBlocker blocker(m_optionWidget); if (!preset->load()) { warnKrita << "failed to load the preset."; } } //qDebug() << "resourceSelected" << resource->name(); setCurrentPaintop(preset); m_presetsPopup->setPresetImage(preset->image()); m_presetsPopup->resourceSelected(resource); } } void KisPaintopBox::setCurrentPaintop(const KoID& paintop) { KisPaintOpPresetSP preset = activePreset(paintop); Q_ASSERT(preset && preset->settings()); //qDebug() << "setCurrentPaintop();" << paintop << preset; setCurrentPaintop(preset); } void KisPaintopBox::setCurrentPaintop(KisPaintOpPresetSP preset) { //qDebug() << "setCurrentPaintop(); " << preset->name(); if (preset == m_resourceProvider->currentPreset()) { if (preset == m_tabletToolMap[m_currTabletToolID].preset) { return; } } Q_ASSERT(preset); const KoID& paintop = preset->paintOp(); m_presetConnections.clear(); if (m_resourceProvider->currentPreset()) { m_resourceProvider->setPreviousPaintOpPreset(m_resourceProvider->currentPreset()); if (m_optionWidget) { m_optionWidget->hide(); } } if (!m_paintopOptionWidgets.contains(paintop)) m_paintopOptionWidgets[paintop] = KisPaintOpRegistry::instance()->get(paintop.id())->createConfigWidget(this); m_optionWidget = m_paintopOptionWidgets[paintop]; KisSignalsBlocker b(m_optionWidget); preset->setOptionsWidget(m_optionWidget); m_optionWidget->setImage(m_viewManager->image()); m_optionWidget->setNode(m_viewManager->activeNode()); m_presetsPopup->setPaintOpSettingsWidget(m_optionWidget); m_resourceProvider->setPaintOpPreset(preset); Q_ASSERT(m_optionWidget && m_presetSelectorPopupButton); m_presetConnections.addConnection(m_optionWidget, SIGNAL(sigConfigurationUpdated()), this, SLOT(slotGuiChangedCurrentPreset())); m_presetConnections.addConnection(m_optionWidget, SIGNAL(sigSaveLockedConfig(KisPropertiesConfigurationSP)), this, SLOT(slotSaveLockedOptionToPreset(KisPropertiesConfigurationSP))); m_presetConnections.addConnection(m_optionWidget, SIGNAL(sigDropLockedConfig(KisPropertiesConfigurationSP)), this, SLOT(slotDropLockedOption(KisPropertiesConfigurationSP))); // load the current brush engine icon for the brush editor toolbar button m_brushEditorPopupButton->slotSetItem(preset); m_presetsPopup->setCurrentPaintOpId(paintop.id()); ////qDebug() << "\tsetting the new preset for" << m_currTabletToolID.uniqueID << "to" << preset->name(); m_paintOpPresetMap[m_resourceProvider->currentPreset()->paintOp()] = preset; m_tabletToolMap[m_currTabletToolID].preset = preset; m_tabletToolMap[m_currTabletToolID].paintOpID = preset->paintOp(); if (m_presetsPopup->currentPaintOpId() != paintop.id()) { // Must change the paintop as the current one is not supported // by the new colorspace. dbgKrita << "current paintop " << paintop.name() << " was not set, not supported by colorspace"; } } void KisPaintopBox::slotUpdateOptionsWidgetPopup() { KisPaintOpPresetSP preset = m_resourceProvider->currentPreset(); KIS_SAFE_ASSERT_RECOVER_RETURN(preset); KIS_SAFE_ASSERT_RECOVER_RETURN(m_optionWidget); m_optionWidget->setConfigurationSafe(preset->settings()); m_presetsPopup->resourceSelected(preset); m_presetsPopup->updateViewSettings(); // the m_viewManager->image() is set earlier, but the reference will be missing when the stamp button is pressed // need to later do some research on how and when we should be using weak shared pointers (WSP) that creates this situation m_optionWidget->setImage(m_viewManager->image()); } KisPaintOpPresetSP KisPaintopBox::defaultPreset(const KoID& paintOp) { QString defaultName = paintOp.id() + ".kpp"; QString path = KoResourcePaths::findResource("kis_defaultpresets", defaultName); KisPaintOpPresetSP preset(new KisPaintOpPreset(path)); if (!preset->load()) { preset = KisPaintOpRegistry::instance()->defaultPreset(paintOp); } Q_ASSERT(preset); Q_ASSERT(preset->valid()); return preset; } KisPaintOpPresetSP KisPaintopBox::activePreset(const KoID& paintOp) { if (m_paintOpPresetMap[paintOp] == 0) { m_paintOpPresetMap[paintOp] = defaultPreset(paintOp); } return m_paintOpPresetMap[paintOp]; } void KisPaintopBox::updateCompositeOp(QString compositeOpID) { if (!m_optionWidget) return; KisSignalsBlocker blocker(m_optionWidget); KisNodeSP node = m_resourceProvider->currentNode(); if (node && node->paintDevice()) { if (!node->paintDevice()->colorSpace()->hasCompositeOp(compositeOpID)) compositeOpID = KoCompositeOpRegistry::instance().getDefaultCompositeOp().id(); { KisSignalsBlocker b1(m_cmbCompositeOp); m_cmbCompositeOp->selectCompositeOp(KoID(compositeOpID)); } if (compositeOpID != m_currCompositeOpID) { m_currCompositeOpID = compositeOpID; } if (compositeOpID == COMPOSITE_ERASE || m_resourceProvider->eraserMode()) { m_eraseModeButton->setChecked(true); } else { m_eraseModeButton->setChecked(false); } } } void KisPaintopBox::setWidgetState(int flags) { if (flags & (ENABLE_COMPOSITEOP | DISABLE_COMPOSITEOP)) { m_cmbCompositeOp->setEnabled(flags & ENABLE_COMPOSITEOP); m_eraseModeButton->setEnabled(flags & ENABLE_COMPOSITEOP); } if (flags & (ENABLE_PRESETS | DISABLE_PRESETS)) { m_presetSelectorPopupButton->setEnabled(flags & ENABLE_PRESETS); m_brushEditorPopupButton->setEnabled(flags & ENABLE_PRESETS); } for (int i = 0; i < 3; ++i) { if (flags & (ENABLE_OPACITY | DISABLE_OPACITY)) m_sliderChooser[i]->getWidget("opacity")->setEnabled(flags & ENABLE_OPACITY); if (flags & (ENABLE_FLOW | DISABLE_FLOW)) m_sliderChooser[i]->getWidget("flow")->setEnabled(flags & ENABLE_FLOW); if (flags & (ENABLE_SIZE | DISABLE_SIZE)) m_sliderChooser[i]->getWidget("size")->setEnabled(flags & ENABLE_SIZE); } } void KisPaintopBox::setSliderValue(const QString& sliderID, qreal value) { for (int i = 0; i < 3; ++i) { KisDoubleSliderSpinBox* slider = m_sliderChooser[i]->getWidget(sliderID); KisSignalsBlocker b(slider); if (sliderID == "opacity" || sliderID == "flow") { // opacity and flows UI stored at 0-100% slider->setValue(value*100); } else { slider->setValue(value); // brush size } } } void KisPaintopBox::slotSetPaintop(const QString& paintOpId) { if (KisPaintOpRegistry::instance()->get(paintOpId) != 0) { KoID id(paintOpId, KisPaintOpRegistry::instance()->get(paintOpId)->name()); //qDebug() << "slotsetpaintop" << id; setCurrentPaintop(id); } } void KisPaintopBox::slotInputDeviceChanged(const KoInputDevice& inputDevice) { TabletToolMap::iterator toolData = m_tabletToolMap.find(inputDevice); //qDebug() << "slotInputDeviceChanged()" << inputDevice.device() << inputDevice.uniqueTabletId(); m_currTabletToolID = TabletToolID(inputDevice); if (toolData == m_tabletToolMap.end()) { KisConfig cfg(true); KisPaintOpPresetResourceServer *rserver = KisResourceServerProvider::instance()->paintOpPresetServer(); KisPaintOpPresetSP preset; if (inputDevice.pointer() == QTabletEvent::Eraser) { preset = rserver->resourceByName(cfg.readEntry(QString("LastEraser_%1").arg(inputDevice.uniqueTabletId()), m_eraserName)); } else { preset = rserver->resourceByName(cfg.readEntry(QString("LastPreset_%1").arg(inputDevice.uniqueTabletId()), m_defaultPresetName)); //if (preset) //qDebug() << "found stored preset " << preset->name() << "for" << inputDevice.uniqueTabletId(); //else //qDebug() << "no preset found for" << inputDevice.uniqueTabletId(); } if (!preset) { preset = rserver->resourceByName(m_defaultPresetName); } if (preset) { //qDebug() << "inputdevicechanged 1" << preset; setCurrentPaintop(preset); } } else { if (toolData->preset) { //qDebug() << "inputdevicechanged 2" << toolData->preset; setCurrentPaintop(toolData->preset); } else { //qDebug() << "inputdevicechanged 3" << toolData->paintOpID; setCurrentPaintop(toolData->paintOpID); } } } void KisPaintopBox::slotCreatePresetFromScratch(QString paintop) { //First try to select an available default preset for that engine. If it doesn't exist, then //manually set the engine to use a new preset. KoID id(paintop, KisPaintOpRegistry::instance()->get(paintop)->name()); KisPaintOpPresetSP preset = defaultPreset(id); slotSetPaintop(paintop); // change the paintop settings area and update the UI if (!preset) { m_presetsPopup->setCreatingBrushFromScratch(true); // disable UI elements while creating from scratch preset = m_resourceProvider->currentPreset(); } else { m_resourceProvider->setPaintOpPreset(preset); preset->setOptionsWidget(m_optionWidget); } m_presetsPopup->resourceSelected(preset); // this helps update the UI on the brush editor } void KisPaintopBox::slotCanvasResourceChanged(int key, const QVariant &value) { if (m_viewManager) { sender()->blockSignals(true); KisPaintOpPresetSP preset = m_viewManager->resourceProvider()->resourceManager()->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value(); if (preset && m_resourceProvider->currentPreset()->name() != preset->name()) { QString compositeOp = preset->settings()->getString("CompositeOp"); updateCompositeOp(compositeOp); resourceSelected(preset); } /** * Update currently selected preset in both the popup widgets */ m_presetsChooserPopup->canvasResourceChanged(preset); m_presetsPopup->currentPresetChanged(preset); if (key == KisCanvasResourceProvider::CurrentCompositeOp) { if (m_resourceProvider->currentCompositeOp() != m_currCompositeOpID) { updateCompositeOp(m_resourceProvider->currentCompositeOp()); } } if (key == KisCanvasResourceProvider::Size) { setSliderValue("size", m_resourceProvider->size()); } if (key == KisCanvasResourceProvider::Opacity) { setSliderValue("opacity", m_resourceProvider->opacity()); } if (key == KisCanvasResourceProvider::Flow) { setSliderValue("flow", m_resourceProvider->flow()); } if (key == KisCanvasResourceProvider::EraserMode) { m_eraseAction->setChecked(value.toBool()); } if (key == KisCanvasResourceProvider::DisablePressure) { m_disablePressureAction->setChecked(value.toBool()); } sender()->blockSignals(false); } } void KisPaintopBox::slotUpdatePreset() { if (!m_resourceProvider->currentPreset()) return; // block updates of avoid some over updating of the option widget m_blockUpdate = true; setSliderValue("size", m_resourceProvider->size()); { qreal opacity = m_resourceProvider->currentPreset()->settings()->paintOpOpacity(); m_resourceProvider->setOpacity(opacity); setSliderValue("opacity", opacity); setWidgetState(ENABLE_OPACITY); } { setSliderValue("flow", m_resourceProvider->currentPreset()->settings()->paintOpFlow()); setWidgetState(ENABLE_FLOW); } { updateCompositeOp(m_resourceProvider->currentPreset()->settings()->paintOpCompositeOp()); setWidgetState(ENABLE_COMPOSITEOP); } m_blockUpdate = false; } void KisPaintopBox::slotSetupDefaultPreset() { KisPaintOpPresetSP preset = defaultPreset(m_resourceProvider->currentPreset()->paintOp()); preset->setOptionsWidget(m_optionWidget); m_resourceProvider->setPaintOpPreset(preset); // tell the brush editor that the resource has changed // so it can update everything m_presetsPopup->resourceSelected(preset); } void KisPaintopBox::slotNodeChanged(const KisNodeSP node) { if (m_previousNode.isValid() && m_previousNode->paintDevice()) disconnect(m_previousNode->paintDevice().data(), SIGNAL(colorSpaceChanged(const KoColorSpace*)), this, SLOT(slotColorSpaceChanged(const KoColorSpace*))); // Reconnect colorspace change of node if (node && node->paintDevice()) { connect(node->paintDevice().data(), SIGNAL(colorSpaceChanged(const KoColorSpace*)), this, SLOT(slotColorSpaceChanged(const KoColorSpace*))); m_resourceProvider->setCurrentCompositeOp(m_currCompositeOpID); m_previousNode = node; slotColorSpaceChanged(node->colorSpace()); } if (m_optionWidget) { m_optionWidget->setNode(node); } } void KisPaintopBox::slotColorSpaceChanged(const KoColorSpace* colorSpace) { m_cmbCompositeOp->validate(colorSpace); } void KisPaintopBox::slotToggleEraseMode(bool checked) { const bool oldEraserMode = m_resourceProvider->eraserMode(); m_resourceProvider->setEraserMode(checked); if (oldEraserMode != checked && m_eraserBrushSizeEnabled) { const qreal currentSize = m_resourceProvider->size(); KisPaintOpSettingsSP settings = m_resourceProvider->currentPreset()->settings(); // remember brush size. set the eraser size to the normal brush size if not set if (checked) { settings->setSavedBrushSize(currentSize); if (qFuzzyIsNull(settings->savedEraserSize())) { settings->setSavedEraserSize(currentSize); } } else { settings->setSavedEraserSize(currentSize); if (qFuzzyIsNull(settings->savedBrushSize())) { settings->setSavedBrushSize(currentSize); } } //update value in UI (this is the main place the value is 'stored' in memory) qreal newSize = checked ? settings->savedEraserSize() : settings->savedBrushSize(); m_resourceProvider->setSize(newSize); } if (oldEraserMode != checked && m_eraserBrushOpacityEnabled) { const qreal currentOpacity = m_resourceProvider->opacity(); KisPaintOpSettingsSP settings = m_resourceProvider->currentPreset()->settings(); // remember brush opacity. set the eraser opacity to the normal brush opacity if not set if (checked) { settings->setSavedBrushOpacity(currentOpacity); if (qFuzzyIsNull(settings->savedEraserOpacity())) { settings->setSavedEraserOpacity(currentOpacity); } } else { settings->setSavedEraserOpacity(currentOpacity); if (qFuzzyIsNull(settings->savedBrushOpacity())) { settings->setSavedBrushOpacity(currentOpacity); } } //update value in UI (this is the main place the value is 'stored' in memory) qreal newOpacity = checked ? settings->savedEraserOpacity() : settings->savedBrushOpacity(); m_resourceProvider->setOpacity(newOpacity); } } void KisPaintopBox::slotSetCompositeMode(int index) { Q_UNUSED(index); QString compositeOp = m_cmbCompositeOp->selectedCompositeOp().id(); m_resourceProvider->setCurrentCompositeOp(compositeOp); } void KisPaintopBox::slotHorizontalMirrorChanged(bool value) { m_resourceProvider->setMirrorHorizontal(value); } void KisPaintopBox::slotVerticalMirrorChanged(bool value) { m_resourceProvider->setMirrorVertical(value); } void KisPaintopBox::sliderChanged(int n) { if (!m_optionWidget) // widget will not exist if the are no documents open return; KisSignalsBlocker blocker(m_optionWidget); // flow and opacity are shown as 0-100% on the UI, but their data is actually 0-1. Convert those two values // back for further work qreal opacity = m_sliderChooser[n]->getWidget("opacity")->value()/100; qreal flow = m_sliderChooser[n]->getWidget("flow")->value()/100; qreal size = m_sliderChooser[n]->getWidget("size")->value(); setSliderValue("opacity", opacity); setSliderValue("flow" , flow); setSliderValue("size" , size); if (m_presetsEnabled) { // IMPORTANT: set the PaintOp size before setting the other properties // it won't work the other way // TODO: why?! m_resourceProvider->setSize(size); m_resourceProvider->setOpacity(opacity); m_resourceProvider->setFlow(flow); KisLockedPropertiesProxySP propertiesProxy = KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(m_resourceProvider->currentPreset()->settings()); propertiesProxy->setProperty("OpacityValue", opacity); propertiesProxy->setProperty("FlowValue", flow); m_optionWidget->setConfigurationSafe(m_resourceProvider->currentPreset()->settings().data()); } else { m_resourceProvider->setOpacity(opacity); } m_presetsPopup->resourceSelected(m_resourceProvider->currentPreset()); } void KisPaintopBox::slotSlider1Changed() { sliderChanged(0); } void KisPaintopBox::slotSlider2Changed() { sliderChanged(1); } void KisPaintopBox::slotSlider3Changed() { sliderChanged(2); } void KisPaintopBox::slotToolChanged(KoCanvasController* canvas, int toolId) { Q_UNUSED(canvas); Q_UNUSED(toolId); if (!m_viewManager->canvasBase()) return; QString id = KoToolManager::instance()->activeToolId(); KisTool* tool = dynamic_cast(KoToolManager::instance()->toolById(m_viewManager->canvasBase(), id)); if (tool) { int flags = tool->flags(); if (flags & KisTool::FLAG_USES_CUSTOM_COMPOSITEOP) { setWidgetState(ENABLE_COMPOSITEOP | ENABLE_OPACITY); } else { setWidgetState(DISABLE_COMPOSITEOP | DISABLE_OPACITY); } if (flags & KisTool::FLAG_USES_CUSTOM_PRESET) { setWidgetState(ENABLE_PRESETS); slotUpdatePreset(); m_presetsEnabled = true; } else { setWidgetState(DISABLE_PRESETS); m_presetsEnabled = false; } if (flags & KisTool::FLAG_USES_CUSTOM_SIZE) { setWidgetState(ENABLE_SIZE | ENABLE_FLOW); } else { setWidgetState(DISABLE_SIZE | DISABLE_FLOW); } } else setWidgetState(DISABLE_ALL); } void KisPaintopBox::slotPreviousFavoritePreset() { if (!m_favoriteResourceManager) return; QVector presets = m_favoriteResourceManager->favoritePresetList(); for (int i=0; i < presets.size(); ++i) { if (m_resourceProvider->currentPreset() && m_resourceProvider->currentPreset()->name() == presets[i]->name()) { if (i > 0) { m_favoriteResourceManager->slotChangeActivePaintop(i - 1); } else { m_favoriteResourceManager->slotChangeActivePaintop(m_favoriteResourceManager->numFavoritePresets() - 1); } //floating message should have least 2 lines, otherwise //preset thumbnail will be too small to distinguish //(because size of image on floating message depends on amount of lines in msg) m_viewManager->showFloatingMessage( i18n("%1\nselected", m_resourceProvider->currentPreset()->name()), QIcon(QPixmap::fromImage(m_resourceProvider->currentPreset()->image()))); return; } } } void KisPaintopBox::slotNextFavoritePreset() { if (!m_favoriteResourceManager) return; QVector presets = m_favoriteResourceManager->favoritePresetList(); for(int i = 0; i < presets.size(); ++i) { if (m_resourceProvider->currentPreset()->name() == presets[i]->name()) { if (i < m_favoriteResourceManager->numFavoritePresets() - 1) { m_favoriteResourceManager->slotChangeActivePaintop(i + 1); } else { m_favoriteResourceManager->slotChangeActivePaintop(0); } m_viewManager->showFloatingMessage( i18n("%1\nselected", m_resourceProvider->currentPreset()->name()), QIcon(QPixmap::fromImage(m_resourceProvider->currentPreset()->image()))); return; } } } void KisPaintopBox::slotSwitchToPreviousPreset() { if (m_resourceProvider->previousPreset()) { //qDebug() << "slotSwitchToPreviousPreset();" << m_resourceProvider->previousPreset(); setCurrentPaintop(m_resourceProvider->previousPreset()); m_viewManager->showFloatingMessage( i18n("%1\nselected", m_resourceProvider->currentPreset()->name()), QIcon(QPixmap::fromImage(m_resourceProvider->currentPreset()->image()))); } } void KisPaintopBox::slotUnsetEraseMode() { m_eraseAction->setChecked(false); } void KisPaintopBox::slotToggleAlphaLockMode(bool checked) { if (checked) { m_alphaLockButton->actions()[0]->setIcon(KisIconUtils::loadIcon("transparency-locked")); } else { m_alphaLockButton->actions()[0]->setIcon(KisIconUtils::loadIcon("transparency-unlocked")); } m_resourceProvider->setGlobalAlphaLock(checked); } void KisPaintopBox::slotDisablePressureMode(bool checked) { if (checked) { m_disablePressureAction->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure")); } else { m_disablePressureAction->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure_locked")); } m_resourceProvider->setDisablePressure(checked); } void KisPaintopBox::slotReloadPreset() { KisSignalsBlocker blocker(m_optionWidget); // Here using the name and fetching the preset from the server was the only way the load was working. Otherwise it was not loading. KisPaintOpPresetResourceServer *rserver = KisResourceServerProvider::instance()->paintOpPresetServer(); QSharedPointer preset = rserver->resourceByName(m_resourceProvider->currentPreset()->name()); if (preset) { preset->load(); } } void KisPaintopBox::slotGuiChangedCurrentPreset() // Called only when UI is changed and not when preset is changed { KisPaintOpPresetSP preset = m_resourceProvider->currentPreset(); { /** * Here we postpone all the settings updates events until the entire writing * operation will be finished. As soon as it is finished, the updates will be * emitted happily (if there were any). */ KisPaintOpPreset::UpdatedPostponer postponer(preset); QStringList preserveProperties; preserveProperties << "lodUserAllowed"; preserveProperties << "lodSizeThreshold"; // clear all the properties before dumping the stuff into the preset, // some of the options add the values incrementally // (e.g. KisPaintOpUtils::RequiredBrushFilesListTag), therefore they // may add up if we pass the same preset multiple times preset->settings()->resetSettings(preserveProperties); m_optionWidget->writeConfigurationSafe(const_cast(preset->settings().data())); } // we should also update the preset strip to update the status of the "dirty" mark m_presetsPopup->resourceSelected(m_resourceProvider->currentPreset()); // TODO!!!!!!!! //m_presetsPopup->updateViewSettings(); } void KisPaintopBox::slotSaveLockedOptionToPreset(KisPropertiesConfigurationSP p) { QMapIterator i(p->getProperties()); while (i.hasNext()) { i.next(); m_resourceProvider->currentPreset()->settings()->setProperty(i.key(), QVariant(i.value())); if (m_resourceProvider->currentPreset()->settings()->hasProperty(i.key() + "_previous")) { m_resourceProvider->currentPreset()->settings()->removeProperty(i.key() + "_previous"); } } slotGuiChangedCurrentPreset(); } void KisPaintopBox::slotDropLockedOption(KisPropertiesConfigurationSP p) { KisSignalsBlocker blocker(m_optionWidget); KisPaintOpPresetSP preset = m_resourceProvider->currentPreset(); { KisPaintOpPreset::DirtyStateSaver dirtySaver(preset); QMapIterator i(p->getProperties()); while (i.hasNext()) { i.next(); if (preset->settings()->hasProperty(i.key() + "_previous")) { preset->settings()->setProperty(i.key(), preset->settings()->getProperty(i.key() + "_previous")); preset->settings()->removeProperty(i.key() + "_previous"); } } } //slotUpdatePreset(); } void KisPaintopBox::slotDirtyPresetToggled(bool value) { if (!value) { slotReloadPreset(); m_presetsPopup->resourceSelected(m_resourceProvider->currentPreset()); m_presetsPopup->updateViewSettings(); } m_dirtyPresetsEnabled = value; KisConfig cfg(false); cfg.setUseDirtyPresets(m_dirtyPresetsEnabled); } void KisPaintopBox::slotEraserBrushSizeToggled(bool value) { m_eraserBrushSizeEnabled = value; KisConfig cfg(false); cfg.setUseEraserBrushSize(m_eraserBrushSizeEnabled); } void KisPaintopBox::slotEraserBrushOpacityToggled(bool value) { m_eraserBrushOpacityEnabled = value; KisConfig cfg(false); cfg.setUseEraserBrushOpacity(m_eraserBrushOpacityEnabled); } void KisPaintopBox::slotUpdateSelectionIcon() { m_hMirrorAction->setIcon(KisIconUtils::loadIcon("symmetry-horizontal")); m_vMirrorAction->setIcon(KisIconUtils::loadIcon("symmetry-vertical")); KisConfig cfg(true); if (!cfg.toolOptionsInDocker() && m_toolOptionsPopupButton) { m_toolOptionsPopupButton->setIcon(KisIconUtils::loadIcon("configure")); } m_presetSelectorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_01")); m_brushEditorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_02")); m_workspaceWidget->setIcon(KisIconUtils::loadIcon("view-choose")); m_eraseAction->setIcon(KisIconUtils::loadIcon("draw-eraser")); m_reloadAction->setIcon(KisIconUtils::loadIcon("view-refresh")); if (m_disablePressureAction->isChecked()) { m_disablePressureAction->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure")); } else { m_disablePressureAction->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure_locked")); } } void KisPaintopBox::slotLockXMirrorToggle(bool toggleLock) { m_resourceProvider->setMirrorHorizontalLock(toggleLock); } void KisPaintopBox::slotLockYMirrorToggle(bool toggleLock) { m_resourceProvider->setMirrorVerticalLock(toggleLock); } void KisPaintopBox::slotHideDecorationMirrorX(bool toggled) { m_resourceProvider->setMirrorHorizontalHideDecorations(toggled); } void KisPaintopBox::slotHideDecorationMirrorY(bool toggled) { m_resourceProvider->setMirrorVerticalHideDecorations(toggled); } void KisPaintopBox::slotMoveToCenterMirrorX() { m_resourceProvider->mirrorHorizontalMoveCanvasToCenter(); } void KisPaintopBox::slotMoveToCenterMirrorY() { m_resourceProvider->mirrorVerticalMoveCanvasToCenter(); } diff --git a/libs/ui/kis_paintop_option.h b/libs/ui/kis_paintop_option.h index 925e24c2cc..e04d32bea7 100644 --- a/libs/ui/kis_paintop_option.h +++ b/libs/ui/kis_paintop_option.h @@ -1,133 +1,133 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2008 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KIS_PAINTOP_OPTION_H #define KIS_PAINTOP_OPTION_H #include #include #include #include #include class QWidget; class QString; class KisPaintopLodLimitations; /** * Base interface for paintop options. A paintop option * can be enabled/disabled, has a configuration page * (for example, a curve), a user-visible name and can * be serialized and deserialized into KisPaintOpPresets * * Because KisPaintOpOption classes create a QWidget in * their constructor (the configuration page) you CANNOT * create those objects in a KisPaintOp. KisPaintOps are * created in non-gui threads. * * Options are disabled by default. */ class KRITAUI_EXPORT KisPaintOpOption : public QObject { Q_OBJECT public: enum PaintopCategory { GENERAL, COLOR, TEXTURE, FILTER, MASKING_BRUSH }; KisPaintOpOption(KisPaintOpOption::PaintopCategory category, bool checked); ~KisPaintOpOption() override; KisPaintOpOption::PaintopCategory category() const; virtual bool isCheckable() const; virtual bool isChecked() const; virtual void setChecked(bool checked); void setLocked(bool value); bool isLocked() const; /** * Reimplement this to use the image in the option widget */ virtual void setImage(KisImageWSP image); virtual void setNode(KisNodeWSP node); void startReadOptionSetting(const KisPropertiesConfigurationSP setting); void startWriteOptionSetting(KisPropertiesConfigurationSP setting) const; QWidget *configurationPage() const; virtual void lodLimitations(KisPaintopLodLimitations *l) const; protected: void setConfigurationPage(QWidget *page); protected: /** * Re-implement this to save the configuration to the paint configuration. */ virtual void writeOptionSetting(KisPropertiesConfigurationSP setting) const { Q_UNUSED(setting); } /** - * Re-implement this to set te widgets with the values in @param setting. + * Re-implement this to set te widgets with the values in @p setting. */ virtual void readOptionSetting(const KisPropertiesConfigurationSP setting) { Q_UNUSED(setting); } protected Q_SLOTS: void emitSettingChanged(); void emitCheckedChanged(); Q_SIGNALS: /** * emit this whenever a setting has changed. It will update the preview */ void sigSettingChanged(); /** * emit this whenever a checked state of the option has changed. It as always * emitted *before* sigSettingChanged() */ void sigCheckedChanged(bool value); protected: bool m_checkable; bool m_locked; private: struct Private; Private* const m_d; }; #endif diff --git a/libs/ui/kis_png_converter.h b/libs/ui/kis_png_converter.h index a8f0ddfd0b..94eaaa9592 100644 --- a/libs/ui/kis_png_converter.h +++ b/libs/ui/kis_png_converter.h @@ -1,142 +1,144 @@ /* * Copyright (c) 2005, 2007 Cyrille Berger * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 _KIS_PNG_CONVERTER_H_ #define _KIS_PNG_CONVERTER_H_ #include #include #include #include "kis_types.h" #include "kis_global.h" #include "kis_annotation.h" #include #include class KoStore; class KisDocument; class KoColorSpace; namespace KisMetaData { class Filter; class Store; } struct KisPNGOptions { KisPNGOptions() : compression(0) , interlace(false) , alpha(true) , exif(true) , iptc(true) , xmp(true) , tryToSaveAsIndexed(true) , saveSRGBProfile(false) , forceSRGB(false) , storeMetaData(false) , storeAuthor(false) , transparencyFillColor(Qt::white) {} int compression; bool interlace; bool alpha; bool exif; bool iptc; bool xmp; bool tryToSaveAsIndexed; bool saveSRGBProfile; bool forceSRGB; bool storeMetaData; bool storeAuthor; QList filters; QColor transparencyFillColor; }; /** * This class allows to import/export a PNG from either a file or a QIODevice. */ // XXX_PROGRESS (pass KoUpdater to the png converter) class KRITAUI_EXPORT KisPNGConverter : public QObject { Q_OBJECT public: /** * Initialize the converter. * @param doc the KisDocument related to the image, can be null if you don't have a KisDocument - * @param adapter the undo adapter to be used by the image, can be null if you don't want to use an undo adapter + * @param batchMode whether to use the batch mode */ KisPNGConverter(KisDocument *doc, bool batchMode = false); ~KisPNGConverter() override; public: /** * Load an image from an URL. If the image is not on a local drive, the image is first downloaded to a * temporary location. - * @param uri the url of the image + * @param filename the file name of the image */ KisImageBuilder_Result buildImage(const QString &filename); /** * Load an image from a QIODevice. * @param iod device to access the data */ KisImageBuilder_Result buildImage(QIODevice* iod); /** * Save a layer to a PNG - * @param uri the url of the destination file + * @param filename the name of the destination file + * @param imageRect the image rectangle to save + * @param xRes resolution along x axis + * @param yRes resolution along y axis * @param device the paint device to save * @param annotationsStart an iterator on the first annotation * @param annotationsEnd an iterator on the last annotation - * @param compression a number between 0 and 9 to specify the compression rate (9 is most compressed) - * @param interlace set to true if you want to generate an interlaced png - * @param alpha set to true if you want to save the alpha channel + * @param options PNG formatting options + * @param metaData image metadata */ KisImageBuilder_Result buildFile(const QString &filename, const QRect &imageRect, const qreal xRes, const qreal yRes, KisPaintDeviceSP device, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd, KisPNGOptions options, KisMetaData::Store* metaData); KisImageBuilder_Result buildFile(QIODevice*, const QRect &imageRect, const qreal xRes, const qreal yRes, KisPaintDeviceSP device, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd, KisPNGOptions options, KisMetaData::Store* metaData); /** * Retrieve the constructed image */ KisImageSP image(); /** * @brief saveDeviceToStore saves the given paint device to the KoStore. If the device is not 8 bits sRGB, it will be converted to 8 bits sRGB. * @return true if the saving succeeds */ static bool saveDeviceToStore(const QString &filename, const QRect &imageRect, const qreal xRes, const qreal yRes, KisPaintDeviceSP dev, KoStore *store, KisMetaData::Store* metaData = 0); static bool isColorSpaceSupported(const KoColorSpace *cs); public Q_SLOTS: virtual void cancel(); private: void progress(png_structp png_ptr, png_uint_32 row_number, int pass); private: png_uint_32 m_max_row; KisImageSP m_image; KisDocument *m_doc; bool m_stop; bool m_batchMode; QString m_path; }; #endif diff --git a/libs/ui/opengl/kis_opengl_image_textures.h b/libs/ui/opengl/kis_opengl_image_textures.h index 32a915536e..f08be2636d 100644 --- a/libs/ui/opengl/kis_opengl_image_textures.h +++ b/libs/ui/opengl/kis_opengl_image_textures.h @@ -1,204 +1,208 @@ /* * Copyright (c) 2005-2007 Adrian Page * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_OPENGL_IMAGE_TEXTURES_H_ #define KIS_OPENGL_IMAGE_TEXTURES_H_ #include #include #include #include "kritaui_export.h" #include "kis_shared.h" #include "canvas/kis_update_info.h" #include "opengl/kis_texture_tile.h" #include "KisOpenGLUpdateInfoBuilder.h" class KisOpenGLImageTextures; typedef KisSharedPtr KisOpenGLImageTexturesSP; class KoColorProfile; class KisTextureTileUpdateInfoPoolCollection; typedef QSharedPointer KisTextureTileInfoPoolSP; class KisProofingConfiguration; typedef QSharedPointer KisProofingConfigurationSP; /** * A set of OpenGL textures that contains the projection of a KisImage. */ class KRITAUI_EXPORT KisOpenGLImageTextures : public KisShared { public: /** * Obtain a KisOpenGLImageTextures object for the given image. * @param image The image * @param monitorProfile The profile of the display device + * @param renderingIntent The rendering intent + * @param conversionFlags The color conversion flags */ static KisOpenGLImageTexturesSP getImageTextures(KisImageWSP image, const KoColorProfile *monitorProfile, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags); /** * Default constructor. */ KisOpenGLImageTextures(); /** * Destructor. */ virtual ~KisOpenGLImageTextures(); /** * \return the image associated with the textures */ KisImageSP image() const; /** * Set the color profile of the display device. - * @param profile The color profile of the display device + * @param monitorProfile The color profile of the display device + * @param renderingIntent The rendering intent + * @param conversionFlags The color conversion flags */ void setMonitorProfile(const KoColorProfile *monitorProfile, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags); /** * Complete initialization can only happen once an OpenGL context has been created. - * @param f Pointer to OpenGL functions. They must already be ininitialized. + * @param f Pointer to OpenGL functions. They must already be initialized. */ void initGL(QOpenGLFunctions *f); void setChannelFlags(const QBitArray &channelFlags); void setProofingConfig(KisProofingConfigurationSP); bool internalColorManagementActive() const; bool setInternalColorManagementActive(bool value); /** * The background checkers texture. */ static const int BACKGROUND_TEXTURE_CHECK_SIZE = 32; static const int BACKGROUND_TEXTURE_SIZE = BACKGROUND_TEXTURE_CHECK_SIZE * 2; /** * Generate a background texture from the given QImage. This is used for the checker * pattern on which the image is rendered. */ void generateCheckerTexture(const QImage & checkImage); GLuint checkerTexture(); void updateConfig(bool useBuffer, int NumMipmapLevels); public: inline QRect storedImageBounds() { return m_storedImageBounds; } inline int xToCol(int x) { return x / m_texturesInfo.effectiveWidth; } inline int yToRow(int y) { return y / m_texturesInfo.effectiveHeight; } inline KisTextureTile* getTextureTileCR(int col, int row) { if (m_initialized) { int tile = row * m_numCols + col; KIS_ASSERT_RECOVER_RETURN_VALUE(m_textureTiles.size() > tile, 0); return m_textureTiles[tile]; } return 0; } inline qreal texelSize() const { Q_ASSERT(m_texturesInfo.width == m_texturesInfo.height); return 1.0 / m_texturesInfo.width; } KisOpenGLUpdateInfoSP updateCache(const QRect& rect, KisImageSP srcImage); KisOpenGLUpdateInfoSP updateCacheNoConversion(const QRect& rect); void recalculateCache(KisUpdateInfoSP info, bool blockMipmapRegeneration); void slotImageSizeChanged(qint32 w, qint32 h); KisOpenGLUpdateInfoBuilder& updateInfoBuilder(); protected: KisOpenGLImageTextures(KisImageWSP image, const KoColorProfile *monitorProfile, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags); void createImageTextureTiles(); void destroyImageTextureTiles(); static bool imageCanShareTextures(); private: void getTextureSize(KisGLTexturesInfo *texturesInfo); void updateTextureFormat(); KisOpenGLUpdateInfoSP updateCacheImpl(const QRect& rect, KisImageSP srcImage, bool convertColorSpace); private: KisImageWSP m_image; QRect m_storedImageBounds; const KoColorProfile *m_monitorProfile; KoColorConversionTransformation::Intent m_renderingIntent; KoColorConversionTransformation::ConversionFlags m_conversionFlags; /** * If the destination color space coincides with the one of the image, * then effectively, there is no conversion happens. That is used * for working with OCIO. */ const KoColorSpace *m_tilesDestinationColorSpace; /** * Shows whether the internal color management should be enabled or not. * Please note that if you disable color management, *but* your image color * space will not be supported (non-RGB), then it will be enabled anyway. * And this valiable will hold the real state of affairs! */ bool m_internalColorManagementActive; GLuint m_checkerTexture; KisGLTexturesInfo m_texturesInfo; int m_numCols; QVector m_textureTiles; QOpenGLFunctions *m_glFuncs; bool m_useOcio; bool m_initialized; KisOpenGLUpdateInfoBuilder m_updateInfoBuilder; private: typedef QMap ImageTexturesMap; static ImageTexturesMap imageTexturesMap; }; #endif // KIS_OPENGL_IMAGE_TEXTURES_H_ diff --git a/libs/ui/qtlockedfile/qtlockedfile.cpp b/libs/ui/qtlockedfile/qtlockedfile.cpp index cb666622f2..d3b7e85213 100644 --- a/libs/ui/qtlockedfile/qtlockedfile.cpp +++ b/libs/ui/qtlockedfile/qtlockedfile.cpp @@ -1,157 +1,157 @@ /**************************************************************************** ** ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://www.qt.io/licensing. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "qtlockedfile.h" /*! \class QtLockedFile \brief The QtLockedFile class extends QFile with advisory locking functions. A file may be locked in read or write mode. Multiple instances of \e QtLockedFile, created in multiple processes running on the same machine, may have a file locked in read mode. Exactly one instance may have it locked in write mode. A read and a write lock cannot exist simultaneously on the same file. The file locks are advisory. This means that nothing prevents another process from manipulating a locked file using QFile or file system functions offered by the OS. Serialization is only guaranteed if all processes that access the file use QtLockedFile. Also, while holding a lock on a file, a process must not open the same file again (through any API), or locks can be unexpectedly lost. The lock provided by an instance of \e QtLockedFile is released whenever the program terminates. This is true even when the program crashes and no destructors are called. */ /*! \enum QtLockedFile::LockMode This enum describes the available lock modes. - \value ReadLock A read lock. - \value WriteLock A write lock. - \value NoLock Neither a read lock nor a write lock. + \var ReadLock A read lock. + \var WriteLock A write lock. + \var NoLock Neither a read lock nor a write lock. */ /*! Constructs an unlocked \e QtLockedFile object. This constructor behaves in the same way as \e QFile::QFile(). \sa QFile::QFile() */ QtLockedFile::QtLockedFile() : QFile() { #ifdef Q_OS_WIN m_semaphore_hnd = 0; m_mutex_hnd = 0; #endif m_lock_mode = NoLock; } /*! Constructs an unlocked QtLockedFile object with file \a name. This constructor behaves in the same way as \e QFile::QFile(const QString&). \sa QFile::QFile() */ QtLockedFile::QtLockedFile(const QString &name) : QFile(name) { #ifdef Q_OS_WIN m_semaphore_hnd = 0; m_mutex_hnd = 0; #endif m_lock_mode = NoLock; } /*! Returns \e true if this object has a in read or write lock; otherwise returns \e false. \sa lockMode() */ bool QtLockedFile::isLocked() const { return m_lock_mode != NoLock; } /*! Returns the type of lock currently held by this object, or \e QtLockedFile::NoLock. \sa isLocked() */ QtLockedFile::LockMode QtLockedFile::lockMode() const { return m_lock_mode; } /*! \fn bool QtLockedFile::lock(LockMode mode, bool block = true) Obtains a lock of type \a mode. If \a block is true, this function will block until the lock is acquired. If \a block is false, this function returns \e false immediately if the lock cannot be acquired. If this object already has a lock of type \a mode, this function returns \e true immediately. If this object has a lock of a different type than \a mode, the lock is first released and then a new lock is obtained. This function returns \e true if, after it executes, the file is locked by this object, and \e false otherwise. \sa unlock(), isLocked(), lockMode() */ /*! \fn bool QtLockedFile::unlock() Releases a lock. If the object has no lock, this function returns immediately. This function returns \e true if, after it executes, the file is not locked by this object, and \e false otherwise. \sa lock(), isLocked(), lockMode() */ /*! \fn QtLockedFile::~QtLockedFile() Destroys the \e QtLockedFile object. If any locks were held, they are released. */ diff --git a/libs/ui/tool/kis_tool_freehand_helper.h b/libs/ui/tool/kis_tool_freehand_helper.h index da4f912f37..39c3c56b9d 100644 --- a/libs/ui/tool/kis_tool_freehand_helper.h +++ b/libs/ui/tool/kis_tool_freehand_helper.h @@ -1,159 +1,166 @@ /* * Copyright (c) 2011 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 __KIS_TOOL_FREEHAND_HELPER_H #define __KIS_TOOL_FREEHAND_HELPER_H #include #include #include "kis_types.h" #include "kritaui_export.h" #include #include "kis_default_bounds.h" #include #include "kis_smoothing_options.h" #include "kundo2magicstring.h" class KoPointerEvent; class KoCanvasResourceProvider; class KisPaintingInformationBuilder; class KisStrokesFacade; class KisPostExecutionUndoAdapter; class KisPaintOp; class KisFreehandStrokeInfo; class KRITAUI_EXPORT KisToolFreehandHelper : public QObject { Q_OBJECT public: KisToolFreehandHelper(KisPaintingInformationBuilder *infoBuilder, const KUndo2MagicString &transactionText = KUndo2MagicString(), KisSmoothingOptions *smoothingOptions = 0); ~KisToolFreehandHelper() override; void setSmoothness(KisSmoothingOptionsSP smoothingOptions); KisSmoothingOptionsSP smoothingOptions() const; bool isRunning() const; void cursorMoved(const QPointF &cursorPos); /** - * @param pixelCoords - The position of the KoPointerEvent, in pixel coordinates. + * @param event The event + * @param pixelCoords The position of the KoPointerEvent, in pixel coordinates. + * @param resourceManager The canvas resource manager + * @param image The image + * @param currentNode The current node + * @param strokesFacade The strokes facade + * @param overrideNode The override node + * @param bounds The bounds */ void initPaint(KoPointerEvent *event, const QPointF &pixelCoords, KoCanvasResourceProvider *resourceManager, KisImageWSP image, KisNodeSP currentNode, KisStrokesFacade *strokesFacade, KisNodeSP overrideNode = 0, KisDefaultBoundsBaseSP bounds = 0); void paintEvent(KoPointerEvent *event); void endPaint(); QPainterPath paintOpOutline(const QPointF &savedCursorPos, const KoPointerEvent *event, const KisPaintOpSettingsSP globalSettings, KisPaintOpSettings::OutlineMode mode) const; int canvasRotation(); void setCanvasRotation(int rotation = 0); bool canvasMirroredH(); void setCanvasHorizontalMirrorState (bool mirrored = false); Q_SIGNALS: /** * The signal is emitted when the outline should be updated * explicitly by the tool. Used by Stabilizer option, because it * paints on internal timer events instead of the on every paint() * event */ void requestExplicitUpdateOutline(); protected: void cancelPaint(); int elapsedStrokeTime() const; void initPaintImpl(qreal startAngle, const KisPaintInformation &pi, KoCanvasResourceProvider *resourceManager, KisImageWSP image, KisNodeSP node, KisStrokesFacade *strokesFacade, KisNodeSP overrideNode = 0, KisDefaultBoundsBaseSP bounds = 0); protected: virtual void createPainters(QVector &strokeInfos, const KisDistanceInformation &startDist); // lo-level methods for painting primitives void paintAt(int strokeInfoId, const KisPaintInformation &pi); void paintLine(int strokeInfoId, const KisPaintInformation &pi1, const KisPaintInformation &pi2); void paintBezierCurve(int strokeInfoId, const KisPaintInformation &pi1, const QPointF &control1, const QPointF &control2, const KisPaintInformation &pi2); // hi-level methods for painting primitives virtual void paintAt(const KisPaintInformation &pi); virtual void paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2); virtual void paintBezierCurve(const KisPaintInformation &pi1, const QPointF &control1, const QPointF &control2, const KisPaintInformation &pi2); private: void paint(KisPaintInformation &info); void paintBezierSegment(KisPaintInformation pi1, KisPaintInformation pi2, QPointF tangent1, QPointF tangent2); void stabilizerStart(KisPaintInformation firstPaintInfo); void stabilizerEnd(); KisPaintInformation getStabilizedPaintInfo(const QQueue &queue, const KisPaintInformation &lastPaintInfo); int computeAirbrushTimerInterval() const; private Q_SLOTS: void finishStroke(); void doAirbrushing(); void doAsynchronousUpdate(bool forceUpdate = false); void stabilizerPollAndPaint(); void slotSmoothingTypeChanged(); private: struct Private; Private * const m_d; }; #endif /* __KIS_TOOL_FREEHAND_HELPER_H */ diff --git a/libs/ui/utils/kis_document_aware_spin_box_unit_manager.h b/libs/ui/utils/kis_document_aware_spin_box_unit_manager.h index ec2143be8c..4431a84afa 100644 --- a/libs/ui/utils/kis_document_aware_spin_box_unit_manager.h +++ b/libs/ui/utils/kis_document_aware_spin_box_unit_manager.h @@ -1,70 +1,70 @@ /* * Copyright (c) 2017 Laurent Valentin Jospin * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KISDOCUMENTAWARESPINBOXUNITMANAGER_H #define KISDOCUMENTAWARESPINBOXUNITMANAGER_H #include "kis_spin_box_unit_manager.h" #include "kis_double_parse_unit_spin_box.h" #include "kritaui_export.h" class KisDocumentAwareSpinBoxUnitManagerBuilder : public KisSpinBoxUnitManagerBuilder { public: KisSpinBoxUnitManager* buildUnitManager(QObject* parent) override; }; /*! * \brief The KisDocumentAwareSpinBoxUnitManager class is a KisSpinBoxUnitManager that is able to connect to the current document to compute transformation for document relative units (the ones that depend of the resolution, or the size in pixels of the image). * \see KisSpinBoxUnitManager */ class KRITAUI_EXPORT KisDocumentAwareSpinBoxUnitManager : public KisSpinBoxUnitManager { Q_OBJECT public: enum PixDir { PIX_DIR_X, PIX_DIR_Y }; //in case the image has not the same x and y resolution, indicate on which direction get the resolution. //! \brief configure a KisDocumentAwareSpinBoxUnitManager for the given spinbox (make the manager a child of the spinbox and attach it to the spinbox). static void setDocumentAwarnessToExistingUnitSpinBox(KisDoubleParseUnitSpinBox* spinBox, bool setUnitFromOutsideToggle = false); //! \brief create a unitSpinBox that is already document aware. static KisDoubleParseUnitSpinBox* createUnitSpinBoxWithDocumentAwarness(QWidget* parent = 0); KisDocumentAwareSpinBoxUnitManager(QObject *parent = 0, int pPixDir = PIX_DIR_X); - //! \reimp \see KisSpinBoxUnitManager + //! \see KisSpinBoxUnitManager qreal getConversionFactor(int dim, QString psymbol) const override; - //! \reimp \see KisSpinBoxUnitManager + //! \see KisSpinBoxUnitManager qreal getConversionConstant(int dim, QString symbol) const override; protected: - //! \reimp \see KisSpinBoxUnitManager + //! \see KisSpinBoxUnitManager virtual bool hasPercent(int unitDim) const override; PixDir pixDir; }; #endif // KISDOCUMENTAWARESPINBOXUNITMANAGER_H diff --git a/libs/ui/widgets/kis_curve_widget.h b/libs/ui/widgets/kis_curve_widget.h index a0301fbe78..719c29093a 100644 --- a/libs/ui/widgets/kis_curve_widget.h +++ b/libs/ui/widgets/kis_curve_widget.h @@ -1,161 +1,161 @@ /* * Copyright (c) 2005 C. Boemann * Copyright (c) 2009 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_CURVE_WIDGET_H #define KIS_CURVE_WIDGET_H // Qt includes. #include #include #include #include #include #include #include #include #include #include class QSpinBox; class KisCubicCurve; /** * KisCurveWidget is a widget that shows a single curve that can be edited * by the user. The user can grab the curve and move it; this creates * a new control point. Control points can be deleted by selecting a point * and pressing the delete key. * * (From: http://techbase.kde.org/Projects/Widgets_and_Classes#KisCurveWidget) * KisCurveWidget allows editing of spline based y=f(x) curves. Handy for cases * where you want the user to control such things as tablet pressure * response, color transformations, acceleration by time, aeroplane lift *by angle of attack. */ class KRITAUI_EXPORT KisCurveWidget : public QWidget { Q_OBJECT Q_PROPERTY(bool pointSelected READ pointSelected NOTIFY pointSelectedChanged); public: friend class CurveEditorItem; /** * Create a new curve widget with a default curve, that is a straight * line from bottom-left to top-right. */ KisCurveWidget(QWidget *parent = 0, Qt::WindowFlags f = 0); ~KisCurveWidget() override; /** * Reset the curve to the default shape */ void reset(void); /** * Enable the guide and set the guide color to the specified color. * * XXX: it seems that the guide feature isn't actually implemented yet? */ void setCurveGuide(const QColor & color); /** * Set a background pixmap. The background pixmap will be drawn under * the grid and the curve. * * XXX: or is the pixmap what is drawn to the left and bottom of the curve * itself? */ void setPixmap(const QPixmap & pix); QPixmap getPixmap(); void setBasePixmap(const QPixmap & pix); QPixmap getBasePixmap(); /** * Whether or not there is a point selected * This does NOT include the first and last points */ bool pointSelected() const; Q_SIGNALS: /** * Emitted whenever a control point has changed position. */ void modified(void); /** * Emitted whenever the status of whether a control point is selected or not changes */ void pointSelectedChanged(); protected Q_SLOTS: void inOutChanged(int); protected: void keyPressEvent(QKeyEvent *) override; void paintEvent(QPaintEvent *) override; void mousePressEvent(QMouseEvent * e) override; void mouseReleaseEvent(QMouseEvent * e) override; void mouseMoveEvent(QMouseEvent * e) override; void leaveEvent(QEvent *) override; void resizeEvent(QResizeEvent *e) override; public: /** * @return get a list with all defined points. If you want to know what the * y value for a given x is on the curve defined by these points, use getCurveValue(). * @see getCurveValue */ KisCubicCurve curve(); /** * Replace the current curve with a curve specified by the curve defined by the control - * points in @param inlist. + * points in @p inlist. */ void setCurve(KisCubicCurve inlist); /** * Connect/disconnect external spinboxes to the curve - * @inMin/@inMax - is the range for input values - * @outMin/@outMax - is the range for output values + * @p inMin / @p inMax - is the range for input values + * @p outMin / @p outMax - is the range for output values */ void setupInOutControls(QSpinBox *in, QSpinBox *out, int inMin, int inMax, int outMin, int outMax); void dropInOutControls(); /** * Handy function that creates new point in the middle - * of the curve and sets focus on the m_intIn field, + * of the curve and sets focus on the @p m_intIn field, * so the user can move this point anywhere in a moment */ void addPointInTheMiddle(); private: class Private; Private * const d; }; #endif /* KIS_CURVE_WIDGET_H */ diff --git a/libs/ui/widgets/kis_curve_widget_p.h b/libs/ui/widgets/kis_curve_widget_p.h index c31b452b7c..ba67893926 100644 --- a/libs/ui/widgets/kis_curve_widget_p.h +++ b/libs/ui/widgets/kis_curve_widget_p.h @@ -1,271 +1,271 @@ /* * Copyright (c) 2005 C. Boemann * Copyright (c) 2009 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 _KIS_CURVE_WIDGET_P_H_ #define _KIS_CURVE_WIDGET_P_H_ #include #include #include enum enumState { ST_NORMAL, ST_DRAG }; /** * Private members for KisCurveWidget class */ class Q_DECL_HIDDEN KisCurveWidget::Private { KisCurveWidget *m_curveWidget; public: Private(KisCurveWidget *parent); /* Dragging variables */ int m_grab_point_index; double m_grabOffsetX; double m_grabOffsetY; double m_grabOriginalX; double m_grabOriginalY; QPointF m_draggedAwayPoint; int m_draggedAwayPointIndex; bool m_readOnlyMode; bool m_guideVisible; QColor m_colorGuide; /* The curve itself */ bool m_splineDirty; KisCubicCurve m_curve; QPixmap m_pix; QPixmap m_pixmapBase; bool m_pixmapDirty; QPixmap *m_pixmapCache; /* In/Out controls */ QSpinBox *m_intIn; QSpinBox *m_intOut; /* Working range of them */ int m_inMin; int m_inMax; int m_outMin; int m_outMax; /** * State functions. * At the moment used only for dragging. */ enumState m_state; inline void setState(enumState st); inline enumState state() const; /*** Internal routines ***/ /** * Common update routines */ void setCurveModified(); void setCurveRepaint(); /** * Convert working range of * In/Out controls to normalized * range of spline (and reverse) */ double io2sp(int x, int min, int max); int sp2io(double x, int min, int max); /** - * Check whether newly created/moved point @pt doesn't overlap - * with any of existing ones from @m_points and adjusts its coordinates. - * @skipIndex is the index of the point, that shouldn't be taken + * Check whether newly created/moved point @p pt doesn't overlap + * with any of existing ones from @p m_points and adjusts its coordinates. + * @p skipIndex is the index of the point, that shouldn't be taken * into account during the search - * (e.g. because it's @pt itself) + * (e.g. because it's @p pt itself) * * Returns false in case the point can't be placed anywhere * without overlapping */ bool jumpOverExistingPoints(QPointF &pt, int skipIndex); /** * Synchronize In/Out spinboxes with the curve */ void syncIOControls(); /** - * Find the nearest point to @pt from m_points + * Find the nearest point to @p pt from m_points */ int nearestPointInRange(QPointF pt, int wWidth, int wHeight) const; /** * Nothing to be said! =) */ inline void drawGrid(QPainter &p, int wWidth, int wHeight); }; KisCurveWidget::Private::Private(KisCurveWidget *parent) { m_curveWidget = parent; } double KisCurveWidget::Private::io2sp(int x, int min, int max) { int rangeLen = max - min; return double(x - min) / rangeLen; } int KisCurveWidget::Private::sp2io(double x, int min, int max) { int rangeLen = max - min; return int(x*rangeLen + 0.5) + min; } bool KisCurveWidget::Private::jumpOverExistingPoints(QPointF &pt, int skipIndex) { Q_FOREACH (const QPointF &it, m_curve.points()) { if (m_curve.points().indexOf(it) == skipIndex) continue; if (fabs(it.x() - pt.x()) < POINT_AREA) pt.rx() = pt.x() >= it.x() ? it.x() + POINT_AREA : it.x() - POINT_AREA; } return (pt.x() >= 0 && pt.x() <= 1.); } int KisCurveWidget::Private::nearestPointInRange(QPointF pt, int wWidth, int wHeight) const { double nearestDistanceSquared = 1000; int nearestIndex = -1; int i = 0; Q_FOREACH (const QPointF & point, m_curve.points()) { double distanceSquared = (pt.x() - point.x()) * (pt.x() - point.x()) + (pt.y() - point.y()) * (pt.y() - point.y()); if (distanceSquared < nearestDistanceSquared) { nearestIndex = i; nearestDistanceSquared = distanceSquared; } ++i; } if (nearestIndex >= 0) { if (fabs(pt.x() - m_curve.points()[nearestIndex].x()) *(wWidth - 1) < 5 && fabs(pt.y() - m_curve.points()[nearestIndex].y()) *(wHeight - 1) < 5) { return nearestIndex; } } return -1; } #define div2_round(x) (((x)+1)>>1) #define div4_round(x) (((x)+2)>>2) void KisCurveWidget::Private::drawGrid(QPainter &p, int wWidth, int wHeight) { /** * Hint: widget size should conform * formula 4n+5 to draw grid correctly * without curious shifts between * spline and it caused by rounding * * That is not mandatory but desirable */ QPalette appPalette = QApplication::palette(); p.setPen(QPen(appPalette.color(QPalette::Background), 1, Qt::SolidLine)); p.drawLine(div4_round(wWidth), 0, div4_round(wWidth), wHeight); p.drawLine(div2_round(wWidth), 0, div2_round(wWidth), wHeight); p.drawLine(div4_round(3*wWidth), 0, div4_round(3*wWidth), wHeight); p.drawLine(0, div4_round(wHeight), wWidth, div4_round(wHeight)); p.drawLine(0, div2_round(wHeight), wWidth, div2_round(wHeight)); p.drawLine(0, div4_round(3*wHeight), wWidth, div4_round(3*wHeight)); } void KisCurveWidget::Private::syncIOControls() { if (!m_intIn || !m_intOut) return; bool somethingSelected = (m_grab_point_index >= 0); m_intIn->setEnabled(somethingSelected); m_intOut->setEnabled(somethingSelected); if (m_grab_point_index >= 0) { m_intIn->blockSignals(true); m_intOut->blockSignals(true); m_intIn->setValue(sp2io(m_curve.points()[m_grab_point_index].x(), m_inMin, m_inMax)); m_intOut->setValue(sp2io(m_curve.points()[m_grab_point_index].y(), m_outMin, m_outMax)); m_intIn->blockSignals(false); m_intOut->blockSignals(false); } else { /*FIXME: Ideally, these controls should hide away now */ } } void KisCurveWidget::Private::setCurveModified() { syncIOControls(); m_splineDirty = true; m_curveWidget->update(); m_curveWidget->emit modified(); } void KisCurveWidget::Private::setCurveRepaint() { m_curveWidget->update(); } void KisCurveWidget::Private::setState(enumState st) { m_state = st; } enumState KisCurveWidget::Private::state() const { return m_state; } #endif /* _KIS_CURVE_WIDGET_P_H_ */ diff --git a/libs/ui/widgets/kis_custom_image_widget.h b/libs/ui/widgets/kis_custom_image_widget.h index e57f9ff2c6..0457d1d4a0 100644 --- a/libs/ui/widgets/kis_custom_image_widget.h +++ b/libs/ui/widgets/kis_custom_image_widget.h @@ -1,101 +1,107 @@ /* This file is part of the Calligra project * Copyright (C) 2005 Thomas Zander * Copyright (C) 2005 C. Boemann * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_CUSTOM_IMAGE_WIDGET_H #define KIS_CUSTOM_IMAGE_WIDGET_H #include "kis_global.h" #include "KoUnit.h" #include "kis_properties_configuration.h" #include "KisOpenPane.h" #include class KisDocument; class KisDocument; enum CustomImageWidgetType { CUSTOM_DOCUMENT, NEW_IMG_FROM_CB }; class WdgNewImage : public QWidget, public Ui::WdgNewImage { Q_OBJECT public: WdgNewImage(QWidget *parent) : QWidget(parent) { setupUi(this); } }; /** * The 'Custom Document' widget in the Krita startup widget. * This class embeds the image size and colorspace to allow the user to select the image properties * for a new empty image document. */ class KisCustomImageWidget : public WdgNewImage { Q_OBJECT public: /** * Constructor. Please note that this class is being used/created by KisDoc. * @param parent the parent widget - * @param doc the document that wants to be altered + * @param defWidth The defined width + * @param defHeight The defined height + * @param resolution The image resolution + * @param defColorModel The defined color model + * @param defColorDepth The defined color depth + * @param defColorProfile The defined color profile + * @param imageName the document that wants to be altered */ KisCustomImageWidget(QWidget *parent, qint32 defWidth, qint32 defHeight, double resolution, const QString & defColorModel, const QString & defColorDepth, const QString & defColorProfile, const QString & imageName); ~KisCustomImageWidget() override; private Q_SLOTS: void widthUnitChanged(int index); void widthChanged(double value); void heightUnitChanged(int index); void heightChanged(double value); void resolutionChanged(double value); void clipboardDataChanged(); void predefinedClicked(int index); void saveAsPredefined(); void setLandscape(); void setPortrait(); void switchWidthHeight(); void createImage(); void switchPortraitLandscape(); void changeDocumentInfoLabel(); protected: KisDocument *createNewImage(); /// Set the number of layers that will be created void setNumberOfLayers(int layers); KisOpenPane *m_openPane; private: double m_width, m_height; quint8 backgroundOpacity() const; void setBackgroundOpacity(quint8 value); void fillPredefined(); void showEvent(QShowEvent *) override; KoUnit m_widthUnit, m_heightUnit; QList m_predefined; }; #endif diff --git a/libs/ui/widgets/kis_image_from_clipboard_widget.h b/libs/ui/widgets/kis_image_from_clipboard_widget.h index c0fa76975f..553f887d10 100644 --- a/libs/ui/widgets/kis_image_from_clipboard_widget.h +++ b/libs/ui/widgets/kis_image_from_clipboard_widget.h @@ -1,53 +1,59 @@ /* This file is part of the Calligra project * Copyright (C) 2005 Thomas Zander * Copyright (C) 2005 C. Boemann * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_IMAGE_FROM_CLIPBOARD_WIDGET_H #define KIS_IMAGE_FROM_CLIPBOARD_WIDGET_H #include "kis_global.h" #include "kis_properties_configuration.h" #include "kis_custom_image_widget.h" #include /** * The 'New image from clipboard' widget in the Krita startup widget. - * This class is an exstension of the KisCustomImageWidget("Custom document" widget" + * This class is an extension of the KisCustomImageWidget("Custom document" widget" */ class KisImageFromClipboard : public KisCustomImageWidget { Q_OBJECT public: /** * Constructor. Please note that this class is being used/created by KisDoc. * @param parent the parent widget - * @param doc the document that wants to be altered + * @param defWidth The defined width + * @param defHeight The defined height + * @param resolution The image resolution + * @param defColorModel The defined color model + * @param defColorDepth The defined color depth + * @param defColorProfile The defined color profile + * @param imageName the document that wants to be altered */ KisImageFromClipboard(QWidget *parent, qint32 defWidth, qint32 defHeight, double resolution, const QString & defColorModel, const QString & defColorDepth, const QString & defColorProfile, const QString & imageName); ~KisImageFromClipboard() override; private Q_SLOTS: void createImage(); void clipboardDataChanged(); private: void createClipboardPreview(); }; #endif diff --git a/libs/ui/widgets/kis_preset_live_preview_view.h b/libs/ui/widgets/kis_preset_live_preview_view.h index 4135851cfc..cb697b1f48 100644 --- a/libs/ui/widgets/kis_preset_live_preview_view.h +++ b/libs/ui/widgets/kis_preset_live_preview_view.h @@ -1,150 +1,150 @@ /* * Copyright (c) 2017 Scott Petrovic * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 _KIS_PRESET_LIVE_PREVIEW_ #define _KIS_PRESET_LIVE_PREVIEW_ #include #include #include #include #include #include "kis_paintop_preset.h" #include "KoColorSpaceRegistry.h" #include "kis_paint_layer.h" #include "kis_painter.h" #include "kis_distance_information.h" #include "kis_painting_information_builder.h" #include #include #include /** * Widget for displaying a live brush preview of your * selected brush. It listens for signalsetting changes * that the brush preset outputs and updates the preview * accordingly. This class can be added to a UI file * similar to how a QGraphicsView is added */ class KisPresetLivePreviewView : public QGraphicsView { Q_OBJECT public: KisPresetLivePreviewView(QWidget *parent); ~KisPresetLivePreviewView(); /** * @brief one time setup for initialization of many variables. * This live preview might be in a UI file, so make sure to * call this before starting to use it */ void setup(); /** * @brief set the current preset from resource manager for the live preview to use. * Good to call this every stroke update in case the preset has changed - * @param the current preset from the resource manager + * @param preset the current preset from the resource manager */ void setCurrentPreset(KisPaintOpPresetSP preset); void updateStroke(); private: /// internally sets the image area for brush preview KisImageSP m_image; /// internally sets the layer area for brush preview KisLayerSP m_layer; /// internally sets the color space for brush preview const KoColorSpace *m_colorSpace; /// the color which is used for rendering the stroke KoColor m_paintColor; /// the scene that can add items like text and the brush stroke image QGraphicsScene *m_brushPreviewScene; /// holds the preview brush stroke data QGraphicsPixmapItem *m_sceneImageItem; /// holds the 'no preview available' text object QGraphicsTextItem *m_noPreviewText; /// holds the width and height of the image of the brush preview /// Probably can later add set functions to make this customizable /// It is hard-coded to 1200 x 400 for right now for image size QRect m_canvasSize; /// convenience variable used internally when positioning the objects /// and points in the scene QPointF m_canvasCenterPoint; /// internal variables for constructing the stroke start and end shape /// there are two points that construct the "S" curve with this KisDistanceInformation m_currentDistance; QPainterPath m_curvedLine; KisPaintInformation m_curvePointPI1; KisPaintInformation m_curvePointPI2; /// internally stores the current preset. /// See setCurrentPreset(KisPaintOpPresetSP preset) /// for setting this externally KisPaintOpPresetSP m_currentPreset; /// holds the current zoom(scale) level of scene float m_scaleFactor; /// internal reference for internal brush size /// used to check if our brush size has changed /// do zooming and other things internally if it has changed float m_currentBrushSize = 1.0; /// the range of brush sizes that will control zooming in/out const float m_minBrushVal = 10.0; const float m_maxBrushVal = 100.0; /// range of scale values. 1.0 == 100% const qreal m_minScale = 1.0; const qreal m_maxScale = 0.3; /// multiplier that is used for lengthening the brush stroke points const float m_minStrokeScale = 0.4; // for smaller brush stroke const float m_maxStrokeScale = 1.0; // for larger brush stroke /** * @brief works as both clearing the previous stroke, providing * striped backgrounds for smudging brushes, and text if there is no preview */ void paintBackground(); /** * @brief creates and performs the actual stroke that goes on top of the background * this is internally and should always be called after the paintBackground() */ void setupAndPaintStroke(); }; #endif diff --git a/libs/ui/widgets/kis_workspace_chooser.cpp b/libs/ui/widgets/kis_workspace_chooser.cpp index 696e7afb5a..382ec5ac27 100644 --- a/libs/ui/widgets/kis_workspace_chooser.cpp +++ b/libs/ui/widgets/kis_workspace_chooser.cpp @@ -1,235 +1,237 @@ /* This file is part of the KDE project * Copyright (C) 2011 Sven Langkamp * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kis_workspace_chooser.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KisResourceServerProvider.h" #include "kis_workspace_resource.h" #include "KisViewManager.h" #include #include #include #include #include #include class KisWorkspaceDelegate : public QAbstractItemDelegate { public: KisWorkspaceDelegate(QObject * parent = 0) : QAbstractItemDelegate(parent) {} ~KisWorkspaceDelegate() override {} /// reimplemented void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const override; /// reimplemented QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex &) const override { return option.decorationSize; } }; void KisWorkspaceDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { if (!index.isValid()) return; KoResourceSP workspace = KoResourceSP(static_cast(index.internalPointer())); QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled) ? QPalette::Active : QPalette::Disabled; QPalette::ColorRole cr = (option.state & QStyle::State_Selected) ? QPalette::HighlightedText : QPalette::Text; painter->setPen(option.palette.color(cg, cr)); if (option.state & QStyle::State_Selected) { painter->fillRect(option.rect, option.palette.highlight()); } else { painter->fillRect(option.rect, option.palette.base()); } painter->drawText(option.rect.x() + 5, option.rect.y() + painter->fontMetrics().ascent() + 5, workspace->name()); } KisWorkspaceChooser::KisWorkspaceChooser(KisViewManager * view, QWidget* parent): QWidget(parent), m_view(view) { KoResourceServer * workspaceServer = KisResourceServerProvider::instance()->workspaceServer(); QSharedPointer workspaceAdapter(new KoResourceServerAdapter(workspaceServer)); KoResourceServer * windowLayoutServer = KisResourceServerProvider::instance()->windowLayoutServer(); QSharedPointer windowLayoutAdapter(new KoResourceServerAdapter(windowLayoutServer)); m_layout = new QGridLayout(this); m_workspaceWidgets = createChooserWidgets(workspaceAdapter, i18n("Workspaces")); m_windowLayoutWidgets = createChooserWidgets(windowLayoutAdapter, i18n("Window layouts")); connect(m_workspaceWidgets.itemChooser, SIGNAL(resourceSelected(KoResourceSP )), this, SLOT(workspaceSelected(KoResourceSP ))); connect(m_workspaceWidgets.saveButton, SIGNAL(clicked(bool)), this, SLOT(slotSaveWorkspace())); connect(m_windowLayoutWidgets.itemChooser, SIGNAL(resourceSelected(KoResourceSP )), this, SLOT(windowLayoutSelected(KoResourceSP ))); connect(m_windowLayoutWidgets.saveButton, SIGNAL(clicked(bool)), this, SLOT(slotSaveWindowLayout())); } KisWorkspaceChooser::ChooserWidgets KisWorkspaceChooser::createChooserWidgets(QSharedPointer adapter, const QString &title) { ChooserWidgets widgets; QLabel *titleLabel = new QLabel(this); QFont titleFont; titleFont.setBold(true); titleLabel->setFont(titleFont); titleLabel->setText(title); widgets.itemChooser = new KoResourceItemChooser(adapter, this); widgets.itemChooser->setItemDelegate(new KisWorkspaceDelegate(this)); widgets.itemChooser->setFixedSize(250, 250); widgets.itemChooser->setRowHeight(30); widgets.itemChooser->setColumnCount(1); widgets.itemChooser->showTaggingBar(false); widgets.saveButton = new QPushButton(i18n("Save")); widgets.nameEdit = new QLineEdit(this); widgets.nameEdit->setPlaceholderText(i18n("Insert name")); widgets.nameEdit->setClearButtonEnabled(true); int firstRow = m_layout->rowCount(); m_layout->addWidget(titleLabel, firstRow, 0, 1, 2); m_layout->addWidget(widgets.itemChooser, firstRow + 1, 0, 1, 2); m_layout->addWidget(widgets.nameEdit, firstRow + 2, 0, 1, 1); m_layout->addWidget(widgets.saveButton, firstRow + 2, 1, 1, 1); return widgets; } KisWorkspaceChooser::~KisWorkspaceChooser() { } void KisWorkspaceChooser::slotSaveWorkspace() { if (!m_view->qtMainWindow()) { return; } KoResourceServer * rserver = KisResourceServerProvider::instance()->workspaceServer(); KisWorkspaceResourceSP workspace(new KisWorkspaceResource(QString())); workspace->setDockerState(m_view->qtMainWindow()->saveState()); m_view->resourceProvider()->notifySavingWorkspace(workspace); workspace->setValid(true); QString saveLocation = rserver->saveLocation(); QString name = m_workspaceWidgets.nameEdit->text(); bool newName = false; if(name.isEmpty()) { newName = true; name = i18n("Workspace"); } QFileInfo fileInfo(saveLocation + name + workspace->defaultFileExtension()); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(saveLocation + name + QString("%1").arg(i) + workspace->defaultFileExtension()); i++; } workspace->setFilename(fileInfo.filePath()); if(newName) { name = i18n("Workspace %1", i); } workspace->setName(name); rserver->addResource(workspace); } void KisWorkspaceChooser::workspaceSelected(KoResourceSP resource) { if (!m_view->qtMainWindow()) { return; } + KisConfig cfg(false); + cfg.writeEntry("CurrentWorkspace", resource->name()); KisWorkspaceResourceSP workspace = resource.staticCast(); KisMainWindow *mainWindow = qobject_cast(m_view->qtMainWindow()); mainWindow->restoreWorkspace(workspace); } void KisWorkspaceChooser::slotSaveWindowLayout() { KisMainWindow *thisWindow = qobject_cast(m_view->qtMainWindow()); if (!thisWindow) return; KisNewWindowLayoutDialog dlg; dlg.setName(m_windowLayoutWidgets.nameEdit->text()); dlg.exec(); if (dlg.result() != QDialog::Accepted) return; QString name = dlg.name(); bool showImageInAllWindows = dlg.showImageInAllWindows(); bool primaryWorkspaceFollowsFocus = dlg.primaryWorkspaceFollowsFocus(); KisWindowLayoutResourceSP layout = KisWindowLayoutResource::fromCurrentWindows(name, KisPart::instance()->mainWindows(), showImageInAllWindows, primaryWorkspaceFollowsFocus, thisWindow); layout->setValid(true); KisWindowLayoutManager::instance()->setShowImageInAllWindowsEnabled(showImageInAllWindows); KisWindowLayoutManager::instance()->setPrimaryWorkspaceFollowsFocus(primaryWorkspaceFollowsFocus, thisWindow->id()); KoResourceServer * rserver = KisResourceServerProvider::instance()->windowLayoutServer(); QString saveLocation = rserver->saveLocation(); bool newName = false; if (name.isEmpty()) { newName = true; name = i18n("Window Layout"); } QFileInfo fileInfo(saveLocation + name + layout->defaultFileExtension()); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(saveLocation + name + QString("%1").arg(i) + layout->defaultFileExtension()); i++; } layout->setFilename(fileInfo.filePath()); if (newName) { name = i18n("Window Layout %1", i); } layout->setName(name); rserver->addResource(layout); } void KisWorkspaceChooser::windowLayoutSelected(KoResourceSP resource) { KisWindowLayoutResourceSP layout = resource.staticCast(); layout->applyLayout(); } diff --git a/libs/vectorimage/libemf/EmfOutput.h b/libs/vectorimage/libemf/EmfOutput.h index 33c63982e8..101d5dd1e5 100644 --- a/libs/vectorimage/libemf/EmfOutput.h +++ b/libs/vectorimage/libemf/EmfOutput.h @@ -1,554 +1,554 @@ /* Copyright 2008 Brad Hards Copyright 2009 Inge Wallin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #ifndef EMFOUTPUT_H #define EMFOUTPUT_H #include "kritavectorimage_export.h" #include #include #include // also provides QSize, QPoint #include #include #include "EmfEnums.h" #include "EmfHeader.h" #include "EmfRecords.h" /** \file Primary definitions for EMF output strategies */ /** Namespace for Enhanced Metafile (EMF) classes */ namespace Libemf { /** Abstract output strategy for EMF Parser */ class KRITAVECTORIMAGE_EXPORT AbstractOutput { public: AbstractOutput() {}; virtual ~AbstractOutput() {}; /** Initialisation routine \param header the EMF Header record */ virtual void init( const Header *header ) = 0; /** Cleanup routine This function is called when the painting is done. Any initializations that are done in init() can be undone here if necessary. \param header the EMF Header record */ virtual void cleanup( const Header *header ) = 0; /** Close-out routine */ virtual void eof() = 0; /** Handler for the EMR_SETPIXELV record type This fills a specified pixel with a particular color \param point the point to fill \param red the red component of the color \param green the green component of the color \param blue the blue component of the color \param reserved reserved component of the color */ virtual void setPixelV( QPoint &point, quint8 red, quint8 green, quint8 blue, quint8 reserved ) = 0; /** Handler for the EMR_CREATEPEN record type This creates a pen object (at position ihPen) using the specified parameters. \param ihPen the internal handle for the pen to be created \param penStyle the pen configuration (style, type) - see the PenStyle enumeration \param x the width of the pen \param y reserved value - ignore this \param red the red component of the pen color \param green the green component of the pen color \param blue the blue component of the pen color \param reserved reserved value - ignore this */ virtual void createPen( quint32 ihPen, quint32 penStyle, quint32 x, quint32 y, quint8 red, quint8 green, quint8 blue, quint8 reserved ) = 0; /** Handler for the EMR_CREATEBRUSHINDIRECT record type */ virtual void createBrushIndirect( quint32 ihBrush, quint32 BrushStyle, quint8 red, quint8 green, quint8 blue, quint8 reserved, quint32 BrushHatch ) = 0; virtual void createMonoBrush( quint32 ihBrush, Bitmap *bitmap ) = 0; /** Handler for the EMR_SETMAPMODE record type. From [MS-EMF]:\n The EMR_SETMAPMODE record specifies the mapping mode of the playback device context. The mapping mode specifies the unit of measure used to transform page-space units into device-space units, and also specifies the orientation of the device's x and y axes. The valid mapping modes are: - 0x01 (MM_TEXT): Each logical unit is mapped to one device pixel. - 0x02 (MM_LOMETRIC): Each logical unit is mapped to 0.1 millimeter - 0x03 (MM_HIMETRIC): Each logical unit is mapped to 0.01 millimeter. - 0x04 (MM_LOENGLISH): Each logical unit is mapped to 0.01 inch. - 0x05 (MM_HIENGLISH): Each logical unit is mapped to 0.001 inch. - 0x06 (MM_TWIPS): Each logical unit is mapped to one twentieth of a printer's point (1/1440 inch). - 0x07 (MM_ISOTROPIC): Logical units are mapped to arbitrary units with equally-scaled axes; that is, one unit along the x-axis is equal to one unit along the y-axis. - 0x08 (MM_ANISOTROPIC): Logical units are mapped to arbitrary units with arbitrarily scaled axes. Note that increasing x is to the right, and increasing y is up, except for MM_TEXT, where it is down. You can expect to get several calls to this function (e.g. MM_ANISOTROPIC, followed by MM_HIMETRIC). If you maintain state based on this call, you probably need to maintain the dimensions / direction separate from the isotropic / anisotropic state. \param mapMode the mapping mode value */ virtual void setMapMode( const quint32 mapMode ) = 0; /** Handler for the EMR_SETMETARGN record type */ virtual void setMetaRgn() = 0; /** Handler for the EMR_SETWINDOWORGEX record type \param origin the origin of the window in logical coordinates */ virtual void setWindowOrgEx( const QPoint &origin ) = 0; /** Handler for the EMR_SETWINDOWEXTEX record type \param size the size of the window in logical coordinates */ virtual void setWindowExtEx( const QSize &size ) = 0; /** Handler for the EMR_SETVIEWPORTORGEX record type \param origin the origin of the viewport in logical coordinates */ virtual void setViewportOrgEx( const QPoint &origin ) = 0; /** Handler for the EMR_SETVIEWPORTEXTEX record type \param size the size of the viewport in logical coordinates */ virtual void setViewportExtEx( const QSize &size ) = 0; /** Handler for the EMR_SETBKMODE record type \param backgroundMode the background fill mode */ virtual void setBkMode( const quint32 backgroundMode ) = 0; /** Handler for the EMR_SETPOLYFILLMODE record type \param polyFillMode the fill mode */ virtual void setPolyFillMode( const quint32 polyFillMode ) = 0; /** Handler for the EMR_SETLAYOUT record type \param layoutMode the layout mode */ virtual void setLayout( const quint32 layoutMode ) = 0; /** Handler for the EMR_MODIFYWORLDTRANSFORM record type There are a range of modes: - 0x01 (MWT_IDENTIFY): Reset current world transform to identity matrix - 0x02 (MWT_LEFTMULTIPLY): Left multiply this matrix with current matrix. - 0x03 (MWT_RIGHTMULTIPLY): Right multiply current matrix with this matrix. - 0x04 (MWT_SET): Set the world transform. \param mode the mode to use. \param M11 \param M12 \param M21 \param M22 \param Dx \param Dy */ virtual void modifyWorldTransform(quint32 mode, float M11, float M12, float M21, float M22, float Dx, float Dy ) = 0; /** Handler for the EMR_SETWORLDTRANSFORM record type \param M11 \param M12 \param M21 \param M22 \param Dx \param Dy */ virtual void setWorldTransform( float M11, float M12, float M21, float M22, float Dx, float Dy ) = 0; /** Select a previously created (or stock) object \param ihObject the reference number for the object to select */ virtual void selectObject( const quint32 ihObject ) = 0; /** Delete a previously created (or stock) object \param ihObject the reference number for the object to delete */ virtual void deleteObject( const quint32 ihObject ) = 0; /** Handler for the EMR_ARC record type \param box the bounding box \param start the coordinates of the point that defines the first radial end point \param end the coordinates of the point that defines the second radial end point */ virtual void arc( const QRect &box, const QPoint &start, const QPoint &end ) = 0; /** Handler for the EMR_CHORD record type \param box the bounding box \param start the coordinates of the point that defines the first radial end point \param end the coordinates of the point that defines the second radial end point */ virtual void chord( const QRect &box, const QPoint &start, const QPoint &end ) = 0; /** Handler for the EMR_PIE record type \param box the bounding box \param start the coordinates of the point that defines the first radial end point \param end the coordinates of the point that defines the second radial end point */ virtual void pie( const QRect &box, const QPoint &start, const QPoint &end ) = 0; /** Handler for the EMR_ELLIPSE record type \param box the bounding box for the ellipse */ virtual void ellipse( const QRect &box ) = 0; /** Handler for the EMR_RECTANGLE record type \param box the bounding box for the rectangle */ virtual void rectangle( const QRect &box ) = 0; /** Handler for the EMR_SETTEXTALIGN record type The textAlignMode is a bit mask, see [MS-WMF] Section 2.1.2.3 for values if the text has a horizontal baseline, [MS-WMF] Section 2.1.2.4 if the text has a vertical baseline. \param textAlignMode the text alignment mode */ virtual void setTextAlign( const quint32 textAlignMode ) = 0; /** Handler for the EMR_SETTEXTCOLOR record type \param red the red component of the text color \param green the blue component of the text color \param blue the blue component of the text color \param reserved an unused value - ignore this */ virtual void setTextColor( const quint8 red, const quint8 green, const quint8 blue, const quint8 reserved ) = 0; /** Handler for the EMR_SETBKCOLOR record type \param red the red component of the background color \param green the blue component of the background color \param blue the blue component of the background color \param reserved an unused value - ignore this */ virtual void setBkColor( const quint8 red, const quint8 green, const quint8 blue, const quint8 reserved ) = 0; /** Handler for the EMR_EXTCREATEFONTINDIRECTW record type - \param extCreateFontIndirectWRecord the contents of the + \param extCreateFontIndirectW the contents of the EMR_EXTCREATEFONTINDIRECTW record */ virtual void extCreateFontIndirectW( const ExtCreateFontIndirectWRecord &extCreateFontIndirectW ) = 0; /** Handler for text rendering, as described in the EMR_EXTTEXTOUTW and EMR_EXTTEXTOUTA record types. \param bounds the bounds used for e.g. clipping - \param texObject The object describing the text. + \param textObject The object describing the text. */ virtual void extTextOut( const QRect &bounds, const EmrTextObject &textObject ) = 0; /** Handler for the EMR_BEGINPATH record type */ virtual void beginPath() = 0; /** Handler for the EMR_CLOSEFIGURE record type */ virtual void closeFigure() = 0; /** Handler for the EMR_ENDPATH record type */ virtual void endPath() = 0; /** Handler for the EMR_MOVETOEX record type \param x the X coordinate of the point to move to \param y the Y coordinate of the point to move to */ virtual void moveToEx( const qint32 x, const qint32 y ) = 0; /** Handler for the EMR_SAVEDC record type */ virtual void saveDC() = 0; /** Handler for the EMR_RESTOREDC record type \param savedDC the device context to restore to (always negative) */ virtual void restoreDC( const qint32 savedDC ) = 0; /** Handler for the EMR_LINETO record type \param finishPoint the point to draw to */ virtual void lineTo( const QPoint &finishPoint ) = 0; /** Handler for the EMR_ARCTO record type \param box the bounding box \param start the coordinates of the point that defines the first radial end point \param end the coordinates of the point that defines the second radial end point */ virtual void arcTo( const QRect &box, const QPoint &start, const QPoint &end ) = 0; /** Handler for the EMR_POLYGON16 record type. This record type specifies how to output a multi-segment filled polygon. \param bounds the bounding rectangle for the line segment \param points the sequence of points that describe the polygon */ virtual void polygon16( const QRect &bounds, const QList points ) = 0; /** Handler for the EMR_POLYLINE record type. This record type specifies how to output a multi-segment line (unfilled polyline). \param bounds the bounding rectangle for the line segments \param points the sequence of points that describe the line \note the line is not meant to be closed (i.e. do not connect the last point to the first point) or filled. */ virtual void polyLine( const QRect &bounds, const QList points ) = 0; /** Handler for the EMR_POLYLINE16 record type. This record type specifies how to output a multi-segment line (unfilled polyline). \param bounds the bounding rectangle for the line segment \param points the sequence of points that describe the line \note the line is not meant to be closed (i.e. do not connect the last point to the first point) or filled. */ virtual void polyLine16( const QRect &bounds, const QList points ) = 0; /** Handler for the EMR_POLYPOLYLINE16 record type. This record type specifies how to output a set of multi-segment line (unfilled polylines). Each vector in the list is a separate polyline \param bounds the bounding rectangle for the line segments \param points the sequence of points that describe the line \note the lines are not meant to be closed (i.e. do not connect the last point to the first point) or filled. */ virtual void polyPolyLine16( const QRect &bounds, const QList< QVector< QPoint > > &points ) = 0; /** Handler for the EMR_POLYPOLYGON16 record type. This record type specifies how to output a set of multi-segment polygons. Each vector in the list is a separate filled polygon. \param bounds the bounding rectangle for the polygons \param points the sequence of points that describe the polygons */ virtual void polyPolygon16( const QRect &bounds, const QList< QVector< QPoint > > &points ) = 0; /** Handler for the EMR_POLYLINETO16 record type. This record type specifies how to output a multi-segment set of lines (unfilled). \param bounds the bounding rectangle for the bezier curves \param points the sequence of points that describe the curves \note the line is not meant to be closed (i.e. do not connect the last point to the first point) or filled. */ virtual void polyLineTo16( const QRect &bounds, const QList points ) = 0; /** Handler for the EMR_POLYBEZIERO16 record type. This record type specifies how to output a multi-segment set of bezier curves (unfilled). \param bounds the bounding rectangle for the bezier curves \param points the sequence of points that describe the curves \note the line is not meant to be closed (i.e. do not connect the last point to the first point) or filled. */ virtual void polyBezier16( const QRect &bounds, const QList points ) = 0; /** Handler for the EMR_POLYLINETO16 record type. This record type specifies how to output a multi-segment set of bezier curves (unfilled), starting at the current point. \param bounds the bounding rectangle for the bezier curves \param points the sequence of points that describe the curves \note the line is not meant to be closed (i.e. do not connect the last point to the first point) or filled. */ virtual void polyBezierTo16( const QRect &bounds, const QList points ) = 0; /** Handler for the EMR_FILLPATH record type. \param bounds the bounding rectangle for the region to be filled. */ virtual void fillPath( const QRect &bounds ) = 0; /** Handler for the EMR_STROKEANDFILLPATH record type. \param bounds the bounding rectangle for the region to be stroked / filled */ virtual void strokeAndFillPath( const QRect &bounds ) = 0; /** Handler for the EMR_STROKEPATH record type. \param bounds the bounding rectangle for the region to be stroked */ virtual void strokePath( const QRect &bounds ) = 0; /** Handler for the EMR_SETCLIPPATH record type. See [MS-EMF] Section 2.1.29 for valid ways to set the path. \param regionMode how to set the clipping path. */ virtual void setClipPath( const quint32 regionMode ) = 0; /** Handler for the EMR_BITBLT record type \param bitBltRecord contents of the record type */ virtual void bitBlt( BitBltRecord &bitBltRecord ) = 0; /** Handler for the EMR_STRETCHBLTMODE record type \param stretchMode the stretch mode */ virtual void setStretchBltMode( const quint32 stretchMode ) = 0; /** Handler for the EMR_STRETCHDIBITS record type \param stretchDiBitsRecord contents of the record type */ virtual void stretchDiBits( StretchDiBitsRecord &stretchDiBitsRecord ) = 0; }; } #endif diff --git a/libs/vectorimage/libemf/EmfRecords.h b/libs/vectorimage/libemf/EmfRecords.h index 03235a4488..e2f0bef9a0 100644 --- a/libs/vectorimage/libemf/EmfRecords.h +++ b/libs/vectorimage/libemf/EmfRecords.h @@ -1,331 +1,333 @@ /* Copyright 2008 Brad Hards Copyright 2009 Inge Wallin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #ifndef EMFRECORDS_H #define EMFRECORDS_H #include #include #include #include // also provides QSize #include #include "Bitmap.h" /** \file Primary definitions for EMF Records */ /** Namespace for Enhanced Metafile (EMF) classes */ namespace Libemf { class EmrTextObject; /*****************************************************************************/ /** Simple representation of an EMR_BITBLT record See MS-EMF Section 2.3.1.2 for details */ class BitBltRecord { public: /** Constructor for record type \param stream the stream to read the record structure from + \param recordSize the size of one record */ BitBltRecord( QDataStream &stream, quint32 recordSize ); ~BitBltRecord(); /** The X origin of the destination rectangle */ qint32 xDest() const { return m_xDest; }; /** The Y origin of the destination rectangle */ qint32 yDest() const { return m_yDest; }; /** The width of the destination rectangle */ qint32 cxDest() const { return m_cxDest; }; /** The height of the destination rectangle */ qint32 cyDest() const { return m_cyDest; }; quint32 rasterOperation() const { return m_BitBltRasterOperation; } QColor bkColorSrc() const { return QColor(m_red, m_green, m_blue, m_reserved); } /** The destination rectangle */ QRect destinationRectangle() const { return QRect( xDest(), yDest(), cxDest(), cyDest() ); }; /** The image to display */ QImage image(); /** Whether there is a valid image in this BitBlt record */ bool hasImage() const; private: // No copying for now, because we will get into trouble with the pointers. // The remedy is to write a real operator=() and BitBltRecord(BitBltRecord&). explicit BitBltRecord(BitBltRecord&); BitBltRecord &operator=(BitBltRecord&); private: QRect m_bounds; qint32 m_xDest; qint32 m_yDest; qint32 m_cxDest; qint32 m_cyDest; quint32 m_BitBltRasterOperation; qint32 m_xSrc; qint32 m_ySrc; QTransform m_XFormSrc; // Background color - elements below quint8 m_red; quint8 m_green; quint8 m_blue; quint8 m_reserved; // Color table interpretation quint32 m_UsageSrc; // The source bitmap meta data quint32 m_offBmiSrc; quint32 m_cbBmiSrc; quint32 m_offBitsSrc; quint32 m_cbBitsSrc; Bitmap *m_bitmap; // The source bitmap //QByteArray m_imageData; //QImage *m_image; }; /*****************************************************************************/ /** Simple representation of an EMR_STRETCHDIBITS record See MS-EMF Section 2.3.1.7 for details */ class StretchDiBitsRecord { public: /** Constructor for record type \param stream the stream to read the record structure from + \param recordSize the size of one record */ StretchDiBitsRecord( QDataStream &stream, quint32 recordSize ); ~StretchDiBitsRecord(); /** The bounds of the affected area, in device units */ QRect bounds() const; /** The X origin of the destination rectangle */ qint32 xDest() const { return m_xDest; }; /** The Y origin of the destination rectangle */ qint32 yDest() const { return m_yDest; }; /** The width of the destination rectangle */ qint32 cxDest() const { return m_cxDest; }; /** The height of the destination rectangle */ qint32 cyDest() const { return m_cyDest; }; /** The destination rectangle */ QRect destinationRectangle() const { return QRect( xDest(), yDest(), cxDest(), cyDest() ); }; /** The X origin of the source rectangle */ qint32 xSrc() const { return m_xSrc; }; /** The Y origin of the source rectangle */ qint32 ySrc() const { return m_ySrc; }; /** The width of the source rectangle */ qint32 cxSrc() const { return m_cxSrc; }; /** The height of the source rectangle */ qint32 cySrc() const { return m_cySrc; }; /** The source rectangle */ QRect sourceRectangle() const { return QRect( xSrc(), ySrc(), cxSrc(), cySrc() ); }; /** The raster operation */ qint32 rasterOperation() const { return m_BitBltRasterOperation; }; quint32 usageSrc() const { return m_UsageSrc; }; /** The image to display */ QImage image(); /** Whether there is a valid image in this StretchDiBitsRecord record */ bool hasImage() const; private: // No copying for now, because we will get into trouble with the pointers. // The remedy is to write a real operator=() and StretchDiBitsRecord(StretchDiBitsRecord&). explicit StretchDiBitsRecord(StretchDiBitsRecord&); StretchDiBitsRecord &operator=(StretchDiBitsRecord&); private: QRect m_Bounds; qint32 m_xDest; qint32 m_yDest; qint32 m_xSrc; qint32 m_ySrc; qint32 m_cxSrc; qint32 m_cySrc; quint32 m_offBmiSrc; quint32 m_cbBmiSrc; quint32 m_offBitsSrc; quint32 m_cbBitsSrc; quint32 m_UsageSrc; quint32 m_BitBltRasterOperation; qint32 m_cxDest; qint32 m_cyDest; Bitmap *m_bitmap; // The source bitmap }; /*****************************************************************************/ /** Simple representation of an EMR_EXTCREATEFONTINDIRECTW record See MS-EMF Section 2.3.7.8 for details */ class ExtCreateFontIndirectWRecord { public: /** Constructor for record type \param stream the stream to read the record structure from \param size the number of bytes in this record */ ExtCreateFontIndirectWRecord( QDataStream &stream, quint32 size ); ~ExtCreateFontIndirectWRecord(); /** The font handle index */ quint32 ihFonts() const { return m_ihFonts; }; /** The height of the font */ qint32 height() const { return m_height; }; /** Whether this is a italic font */ quint8 italic() const { return m_italic; }; /** Whether this is a underlined font */ quint8 underline() const { return m_underline; }; /** The weight of this font */ quint32 weight() const { return m_weight; }; /** The name of the font face */ QString fontFace() const { return m_facename; }; private: quint32 m_ihFonts; qint32 m_height; qint32 m_width; qint32 m_escapement; qint32 m_orientation; qint32 m_weight; quint8 m_italic; quint8 m_underline; quint8 m_strikeout; quint8 m_charSet; quint8 m_outPrecision; quint8 m_clipPrecision; quint8 m_quality; quint8 m_pitchAndFamily; QString m_facename; QString m_fullName; QString m_style; QString m_script; // Routine to throw away a specific number of bytes void soakBytes( QDataStream &stream, int numBytes ); }; } #endif diff --git a/libs/vectorimage/libsvm/SvmAbstractBackend.h b/libs/vectorimage/libsvm/SvmAbstractBackend.h index 6e6de55a51..d053b0c1de 100644 --- a/libs/vectorimage/libsvm/SvmAbstractBackend.h +++ b/libs/vectorimage/libsvm/SvmAbstractBackend.h @@ -1,105 +1,105 @@ /* Copyright 2009 Inge Wallin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #ifndef SVMABSTRACTBACKEND_H #define SVMABSTRACTBACKEND_H #include "kritavectorimage_export.h" #include "SvmEnums.h" #include "SvmStructs.h" #include "SvmGraphicsContext.h" class QPoint; class QRect; class QPolygon; class QString; /** \file Primary definitions for SVM output backend */ /** Namespace for StarView Metafile (SVM) classes */ namespace Libsvm { /** Abstract output strategy for SVM Parser */ class KRITAVECTORIMAGE_EXPORT SvmAbstractBackend { public: SvmAbstractBackend() {}; virtual ~SvmAbstractBackend() {}; /** Initialisation routine \param header the SVM Header record */ virtual void init(const SvmHeader &header) = 0; /** Cleanup routine This function is called when the parsing is done. Any initializations that are done in init() can be undone here if necessary. */ virtual void cleanup() = 0; /** Close-out routine */ virtual void eof() = 0; virtual void rect(SvmGraphicsContext &context, const QRect &rect) = 0; /** Handler META_POLYLINE_ACTION This action type specifies how to output a multi-segment line (unfilled polyline). \param context the graphics context to be used when drawing the polyline - \param polygon the sequence of points that describe the line + \param polyline the sequence of points that describe the line \note the line is not meant to be closed nor filled, i.e. do not connect the last point to the first point. */ virtual void polyLine(SvmGraphicsContext &context, const QPolygon &polyline) = 0; virtual void polygon(SvmGraphicsContext &context, const QPolygon &polygon) = 0; virtual void polyPolygon(SvmGraphicsContext &context, const QList &polyPolygon) = 0; virtual void textArray(SvmGraphicsContext &context, const QPoint &point, const QString &string, quint16 startIndex, quint16 len, quint32 dxArrayLen, qint32 *dxArray) = 0; }; } #endif diff --git a/libs/vectorimage/libsvm/SvmPainterBackend.h b/libs/vectorimage/libsvm/SvmPainterBackend.h index fc89b0b7d7..2d2e285113 100644 --- a/libs/vectorimage/libsvm/SvmPainterBackend.h +++ b/libs/vectorimage/libsvm/SvmPainterBackend.h @@ -1,116 +1,116 @@ /* Copyright 2009 Inge Wallin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #ifndef SVMPAINTERBACKEND_H #define SVMPAINTERBACKEND_H #include "SvmAbstractBackend.h" #include "kritavectorimage_export.h" #include #include #include "SvmEnums.h" #include "SvmStructs.h" #include "SvmGraphicsContext.h" class QRect; class QPolygon; class QPainter; /** \file Primary definitions for SVM output backend */ /** Namespace for StarView Metafile (SVM) classes */ namespace Libsvm { /** Painter output strategy for SVM Parser */ class KRITAVECTORIMAGE_EXPORT SvmPainterBackend : public SvmAbstractBackend { public: SvmPainterBackend(QPainter *painter, const QSize &outputSize); ~SvmPainterBackend() override; /** Initialisation routine \param header the SVM Header record */ void init(const SvmHeader &header) override; /** Cleanup routine This function is called when the painting is done. Any initializations that are done in init() can be undone here if necessary. */ void cleanup() override; /** Close-out routine */ void eof() override; void rect( SvmGraphicsContext &context, const QRect &rect ) override; /** Handler META_POLYLINE_ACTION This action type specifies how to output a multi-segment line (unfilled polyline). \param context the graphics context to be used when drawing the polyline - \param polygon the sequence of points that describe the line + \param polyline the sequence of points that describe the line \note the line is not meant to be closed (i.e. do not connect the last point to the first point) or filled. */ void polyLine(SvmGraphicsContext &context, const QPolygon &polyline) override; void polygon(SvmGraphicsContext &context, const QPolygon &polygon) override; void polyPolygon(SvmGraphicsContext &context, const QList &polyPolygon) override; void textArray(SvmGraphicsContext &context, const QPoint &point, const QString &string, quint16 startIndex, quint16 len, quint32 dxArrayLen, qint32 *dxArray) override; private: void updateFromGraphicscontext(SvmGraphicsContext &context); private: QPainter *m_painter; QSize m_outputSize; QTransform m_outputTransform; }; } #endif diff --git a/libs/widgets/KisDlgInternalColorSelector.h b/libs/widgets/KisDlgInternalColorSelector.h index ff55bb3ae7..ebb4bb6195 100644 --- a/libs/widgets/KisDlgInternalColorSelector.h +++ b/libs/widgets/KisDlgInternalColorSelector.h @@ -1,194 +1,195 @@ /* * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KISDLGINTERNALCOLORSELECTOR_H #define KISDLGINTERNALCOLORSELECTOR_H #include "kritawidgets_export.h" #include "KoColor.h" #include "KoColorSpace.h" #include "KoColorDisplayRendererInterface.h" #include "KoColorSet.h" #include #include "KisScreenColorPickerBase.h" #include "ui_WdgDlgInternalColorSelector.h" /** * @brief The KisInternalColorSelector class * * A non-modal color selector dialog that is not a plugin and can thus be used for filters. */ class KRITAWIDGETS_EXPORT KisDlgInternalColorSelector : public QDialog { Q_OBJECT static std::function s_screenColorPickerFactory; public: static void setScreenColorPickerFactory(std::function f) { s_screenColorPickerFactory = f; } struct Config { Config() : modal(true), visualColorSelector(true), paletteBox(true), screenColorPicker(true), prevNextButtons(true), hexInput(true), useAlpha(false){} bool modal; bool visualColorSelector; bool paletteBox; bool screenColorPicker; bool prevNextButtons; bool hexInput; bool useAlpha; }; KisDlgInternalColorSelector(QWidget* parent, KoColor color, Config config, const QString &caption, const KoColorDisplayRendererInterface *displayRenderer = KoDumbColorDisplayRenderer::instance()); ~KisDlgInternalColorSelector() override; /** * @brief slotColorSpaceChanged * Color space has changed, use this dialog to change the colorspace. */ void colorSpaceChanged(const KoColorSpace *cs); /** * @brief lockUsedColorSpace * Lock the used colorspace of this selector. * @param cs */ void lockUsedColorSpace(const KoColorSpace *cs); /** * @brief setDisplayRenderer * Set the display renderer. This is necessary for HDR color manage support. * @param displayRenderer */ void setDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer); /** * @brief getModalColorDialog * Execute this dialog modally. The function returns * the KoColor you want. * @param color - The current color. Make sure this is in the color space you want your * end color to be in. - * @param chooseAlpha - Whether or not the alpha-choosing functionality should be used. + * @param parent parent widget. + * @param caption the dialog caption. */ static KoColor getModalColorDialog(const KoColor color, QWidget* parent = Q_NULLPTR, QString caption = QString()); /** * @brief getCurrentColor * @return gives currently active color; */ KoColor getCurrentColor(); void chooseAlpha(bool chooseAlpha); Q_SIGNALS: /** * @brief signalForegroundColorChosen * The most important signal. This will sent out when a color has been picked from the selector. * There will be a small delay to make sure that the selector causes too many updates. * * Do not connect this to slotColorUpdated. * @param color The new color chosen */ void signalForegroundColorChosen(KoColor color); public Q_SLOTS: /** * @brief slotColorUpdated * Very important slot. Is connected to krita's resources to make sure it has * the currently active color. It's very important that this function is able to understand * when the signal came from itself. * @param newColor This is the new color. */ void slotColorUpdated(KoColor newColor); /** * @brief slotSetColorFromPatch * update current color from kocolorpatch. * @param patch */ void slotSetColorFromPatch(KoColorPatch* patch); /** * @brief setPreviousColor * set the previous color. */ void setPreviousColor(KoColor c); void reject() override; private Q_SLOTS: /** * @brief slotLockSelector * This slot will prevent the color from being updated. */ void slotLockSelector(); /** * @brief slotConfigurationChanged * Wrapper slot for changes to the colorspace. */ void slotConfigurationChanged(); void endUpdateWithNewColor(); /** * @brief slotFinishUp * This is called when the selector is closed, for saving the current palette. */ void slotFinishUp(); /** * @brief slotSetColorFromHex * Update from the hex color input. */ void slotSetColorFromHex(); void slotChangePalette(KoColorSetSP set); protected: void showEvent(QShowEvent *event) override; private: void focusInEvent(QFocusEvent *) override; /** * @brief updateAllElements * Updates each widget with the new element, and if it's responsible for the update sents * a signal out that there's a new color. */ void updateAllElements(QObject *source); private: Ui_WdgDlgInternalColorSelector *m_ui; struct Private; //The private struct const QScopedPointer m_d; //the private pointer }; #endif // KISDLGINTERNALCOLORSELECTOR_H diff --git a/libs/widgets/KisPaletteModel.h b/libs/widgets/KisPaletteModel.h index ca2c71a5dd..fdf0e4fc6d 100644 --- a/libs/widgets/KisPaletteModel.h +++ b/libs/widgets/KisPaletteModel.h @@ -1,179 +1,180 @@ /* * Copyright (c) 2013 Sven Langkamp * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_PALETTEMODEL_H #define KIS_PALETTEMODEL_H #include #include #include #include #include "kritawidgets_export.h" #include #include class KoColorSet; class KisPaletteView; /** * @brief The KisPaletteModel class * This, together with KisPaletteView and KisPaletteDelegate forms a mvc way to access kocolorsets. * A display renderer is given to this model to convert KoColor to QColor when * colors are requested */ class KRITAWIDGETS_EXPORT KisPaletteModel : public QAbstractTableModel { Q_OBJECT public: explicit KisPaletteModel(QObject* parent = Q_NULLPTR); ~KisPaletteModel() override; enum AdditionalRoles { IsGroupNameRole = Qt::UserRole + 1, CheckSlotRole, GroupNameRole, RowInGroupRole }; public /* overridden methods */: // QAbstractTableModel QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex& parent = QModelIndex()) const override; /** * @brief index * @param row * @param column * @param parent * @return the index of for the data at row, column * if the data is a color entry, the internal pointer points to the group * the entry belongs to, and the row and column are row number and column * number inside the group. * if the data is a group, the row number and group number is Q_INFINIFY, * and the internal pointer also points to the group */ QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; Qt::ItemFlags flags(const QModelIndex& index) const override; /** * @brief dropMimeData * This is an overridden function that handles dropped mimedata. * right now only colorsetentries and colorsetgroups are handled. * @return */ bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; /** * @brief mimeData * gives the mimedata for a kocolorsetentry or a kocolorsetgroup. * @param indexes * @return the mimedata for the given indices */ QMimeData *mimeData(const QModelIndexList &indexes) const override; QStringList mimeTypes() const override; Qt::DropActions supportedDropActions() const override; /** * @brief setData * setData is not used as KoColor is not a QVariant * use setEntry, addEntry and removeEntry instead */ // TODO Used QVariant::setValue and QVariant.value to implement this // bool setData(const QModelIndex &index, const QVariant &value, int role) override; Q_SIGNALS: /** * @brief sigPaletteModified * emitted when palette associated with the model is modified */ void sigPaletteModified(); /** * @brief sigPaletteChanged * emitted when the palette associated with the model is made another one */ void sigPaletteChanged(); public /* methods */: /** * @brief addEntry * proper function to handle adding entries. * @return whether successful. */ bool addEntry(const KisSwatch &entry, const QString &groupName = KoColorSet::GLOBAL_GROUP_NAME); void setEntry(const KisSwatch &entry, const QModelIndex &index); /** * @brief removeEntry * proper function to remove the colorsetentry at the given index. * The consolidates both removeentry and removegroup. - * @param keepColors: This bool determines whether, when deleting a group, + * @param index the given index + * @param keepColors This bool determines whether, when deleting a group, * the colors should be added to the default group. This is usually desirable, * so hence the default is true. * @return if successful */ bool removeEntry(const QModelIndex &index, bool keepColors=true); void removeGroup(const QString &groupName, bool keepColors); bool renameGroup(const QString &groupName, const QString &newName); void addGroup(const KisSwatchGroup &group); void setRowNumber(const QString &groupName, int rowCount); void clear(); KisSwatch getEntry(const QModelIndex &index) const; void setPalette(KoColorSetSP colorSet); KoColorSetSP colorSet() const; QModelIndex indexForClosest(const KoColor &compare); int indexRowForInfo(const KisSwatchGroup::SwatchInfo &info); public Q_SLOTS: private Q_SLOTS: void slotDisplayConfigurationChanged(); void slotPaletteModified(); private /* methods */: QVariant dataForGroupNameRow(const QModelIndex &idx, int role) const; QVariant dataForSwatch(const QModelIndex &idx, int role) const; int rowNumberInGroup(int rowInModel) const; int groupNameRowForRow(int rowInModel) const; int groupNameRowForName(const QString &groupName); void resetGroupNameRows(); /** * Installs a display renderer object for a palette that will * convert the KoColor to the displayable QColor. Default is the * dumb renderer. */ void setDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer); private /* member variables */: QSharedPointer m_colorSet; QPointer m_displayRenderer; QMap m_rowGroupNameMap; friend class KisPaletteView; }; #endif diff --git a/libs/widgets/KisVisualColorSelectorShape.h b/libs/widgets/KisVisualColorSelectorShape.h index ba76d7280b..a24219a26c 100644 --- a/libs/widgets/KisVisualColorSelectorShape.h +++ b/libs/widgets/KisVisualColorSelectorShape.h @@ -1,234 +1,236 @@ /* * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 KIS_VISUAL_COLOR_SELECTOR_SHAPE_H #define KIS_VISUAL_COLOR_SELECTOR_SHAPE_H #include #include #include #include #include #include #include #include "KoColorDisplayRendererInterface.h" #include "KisVisualColorSelector.h" #include "KisColorSelectorConfiguration.h" /** * @brief The KisVisualColorSelectorShape class * A 2d widget can represent at maximum 2 coordinates. * So first decide howmany coordinates you need. (onedimensional, or twodimensional) * Then the model, (Channel, HSV, HSL, HSI, YUV). Channel is the raw color channels. * When it finds a non-implemented feature it'll return to Channel. * Then, select the channels you wish to be affected. This uses the model, so for cmyk * the channel is c=0, m=1, y=2, k=3, but for hsv, hue=0, sat=1, and val=2 * These can also be set with 'slotsetactive channels'. * Then finally, connect the displayrenderer, you can also do this with 'setdisplayrenderer' * * Either way, this class is made to be subclassed, with a few virtuals so that the geometry * can be calculated properly. */ class KisVisualColorSelectorShape : public QWidget { Q_OBJECT public: /** * @brief The Dimensions enum * Whether or not the shape is single or two dimensional. **/ enum Dimensions{onedimensional, twodimensional}; enum ColorModel{Channel, HSV, HSL, HSI, HSY, YUV}; explicit KisVisualColorSelectorShape(QWidget *parent, KisVisualColorSelectorShape::Dimensions dimension, KisVisualColorSelectorShape::ColorModel model, const KoColorSpace *cs, int channel1, int channel2, const KoColorDisplayRendererInterface *displayRenderer = KoDumbColorDisplayRenderer::instance()); ~KisVisualColorSelectorShape() override; /** * @brief getCursorPosition * @return current cursor position in shape-coordinates. */ QPointF getCursorPosition(); /** * @brief getDimensions * @return whether this is a single or twodimensional widget. */ Dimensions getDimensions(); /** * @brief getColorModel * @return the model of this widget. */ ColorModel getColorModel(); /** * @brief getPixmap * @return the pixmap of the gradient, for drawing on with a subclass. * the pixmap will not change unless 'm_d->setPixmap=true' which is toggled by * refresh and update functions. */ bool imagesNeedUpdate() const; QImage getImageMap(); /** * @brief setFullImage * Set the full widget image to be painted. * @param full this should be the full image. */ void setFullImage(QImage full); /** * @brief getCurrentColor * @return the current kocolor */ KoColor getCurrentColor(); /** * @brief setDisplayRenderer * disconnect the old display renderer if needed and connect the new one. * @param displayRenderer */ void setDisplayRenderer (const KoColorDisplayRendererInterface *displayRenderer); /** * @brief getColorFromConverter * @param c a koColor. * @return get the qcolor from the given kocolorusing this widget's display renderer. */ QColor getColorFromConverter(KoColor c); /** * @brief getSpaceForSquare * @param geom the full widget rectangle * @return rectangle with enough space for second widget */ virtual QRect getSpaceForSquare(QRect geom) = 0; virtual QRect getSpaceForCircle(QRect geom) = 0; virtual QRect getSpaceForTriangle(QRect geom) = 0; /** * @brief forceImageUpdate * force the image to recache. */ void forceImageUpdate(); /** * @brief setBorderWidth * set the border of the single dimensional selector. * @param width */ virtual void setBorderWidth(int width) = 0; /** * @brief getChannels * get used channels * @return */ QVector getChannels(); /** * @brief setHSX * This is for the cursor not to change when selecting * black, white, and desaturated values. Will not change the non-native values. * @param hsx the hsx value. + * @param wrangler defines whether this docker will update luminosity if there's not at the least 3\% more variation */ void setHSX(QVector hsx, bool wrangler=false); /** * @brief getHSX sets the sat and hue so they won't * switch around much. * @param hsx the hsx values. + * @param wrangler defines whether this docker will update luminosity if there's not at the least 3\% more variation * @return returns hsx, corrected. */ QVector getHSX(QVector hsx, bool wrangler= false); Q_SIGNALS: void sigNewColor(KoColor col); void sigHSXchange(); public Q_SLOTS: /** * @brief setColor * Set this widget's current color and change the cursor position. * @param c */ void setColor(KoColor c); /** * @brief setColorFromSibling * set this widget's current color, but don't change the cursor position, * instead sent out a signal of the new color. * @param c */ void setColorFromSibling(KoColor c); /** * @brief slotSetActiveChannels * Change the active channels if necessary. * @param channel1 used by single and twodimensional widgets. * @param channel2 only used by twodimensional widgets. */ void slotSetActiveChannels(int channel1, int channel2); /** * @brief updateFromChangedDisplayRenderer * for updating from the display renderer... not sure why this one is public. */ void updateFromChangedDisplayRenderer(); protected: void mousePressEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; void paintEvent(QPaintEvent*) override; private: struct Private; const QScopedPointer m_d; /** * @brief convertShapeCoordinateToWidgetCoordinate * @return take the position in the shape and convert it to screen coordinates. */ virtual QPointF convertShapeCoordinateToWidgetCoordinate(QPointF) = 0; /** * @brief convertWidgetCoordinateToShapeCoordinate * Convert a coordinate in the widget's height/width to a shape coordinate. * @param coordinate the position your wish to have the shape coordinates of. */ virtual QPointF convertWidgetCoordinateToShapeCoordinate(QPoint coordinate) = 0; /** * @brief updateCursor * Update the cursor position. */ void updateCursor(); QPointF convertKoColorToShapeCoordinate(KoColor c); KoColor convertShapeCoordinateToKoColor(QPointF coordinates, bool cursor = false); /** * @brief getPixmap * @return the pixmap of this shape. */ virtual QRegion getMaskMap() = 0; virtual void drawCursor() = 0; QVector convertvectorqrealTofloat(QVector real); QVector convertvectorfloatToqreal(QVector vloat); }; #endif diff --git a/libs/widgets/KoDialog.h b/libs/widgets/KoDialog.h index 0a454e4fa2..b7a40320b8 100644 --- a/libs/widgets/KoDialog.h +++ b/libs/widgets/KoDialog.h @@ -1,835 +1,835 @@ /* This file is part of the KDE Libraries * Copyright (C) 1998 Thomas Tanghus (tanghus@earthling.net) * Additions 1999-2000 by Espen Sand (espen@kde.org) * and Holger Freyther * 2005-2009 Olivier Goffart * 2006 Tobias Koenig * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KODIALOG_H #define KODIALOG_H class QPushButton; class QMenu; class KoDialogPrivate; #include #include #include #include /** * @short A dialog base class with standard buttons and predefined layouts. * * Provides basic functionality needed by nearly all dialogs. * * It offers the standard action buttons you'd expect to find in a * dialog as well as the capability to define at most three configurable * buttons. You can define a main widget that contains your specific * dialog layout * * The class takes care of the geometry management. You only need to define * a minimum size for the widget you want to use as the main widget. * * By default, the dialog is non-modal. * * Standard buttons (action buttons):\n * * You select which buttons should be displayed, but you do not choose the * order in which they are displayed. This ensures a standard interface in * KDE. The button order can be changed, but this ability is only available * for a central KDE control tool. The following buttons are available: * OK, Cancel/Close, Apply/Try, Default, Help and three user definable * buttons: User1, User2 and User3. You must specify the text of the UserN * buttons. Each button emit a signal, so you can choose to connect that signal. * * The default action of the Help button will open the help system if you have * provided a path to the help text. * The default action of Ok and Cancel will run QDialog::accept() and QDialog::reject(), * which you can override by reimplementing slotButtonClicked(). The default * action of the Close button will close the dialog. * * Note that the KoDialog will animate a button press * when the user presses Escape. The button that is enabled is either Cancel, * Close or the button that is defined by setEscapeButton(). * Your custom dialog code should reimplement the keyPressEvent and * animate the cancel button so that the dialog behaves like regular * dialogs. * * Layout:\n * * The dialog consists of a help area on top (becomes visible if you define * a help path and use enableLinkedHelp()), the main area which is * the built-in dialog face or your own widget in the middle and by default * a button box at the bottom. The button box can also be placed at the * right edge (to the right of the main widget). Use * setButtonsOrientation() to control this behavior. A separator * can be placed above the button box (or to the left when the button box * is at the right edge). * * Standard compliance:\n * * The marginHint() and spacingHint() sizes shall be used * whenever you lay out the interior of a dialog. One special note. If * you make your own action buttons (OK, Cancel etc), the space * between the buttons shall be spacingHint(), whereas the space * above, below, to the right and to the left shall be marginHint(). * If you add a separator line above the buttons, there shall be a * marginHint() between the buttons and the separator and a * marginHint() above the separator as well. * * Example:\n * * \code * KoDialog *dialog = new KoDialog( this ); * dialog->setCaption( "My title" ); * dialog->setButtons( KoDialog::Ok | KoDialog::Cancel | KoDialog::Apply ); * * FooWidget *widget = new FooWidget( dialog ); * dialog->setMainWidget( widget ); * connect( dialog, SIGNAL( applyClicked() ), widget, SLOT( save() ) ); * connect( dialog, SIGNAL( okClicked() ), widget, SLOT( save() ) ); * connect( widget, SIGNAL( changed( bool ) ), dialog, SLOT( enableButtonApply( bool ) ) ); * * dialog->enableButtonApply( false ); * dialog->show(); * \endcode * * \image html kdialog.png "KDE Dialog example" * * This class can be used in many ways. Note that most KDE ui widgets * and many of KDE core applications use the KoDialog so for more * inspiration you should study the code for these. * * * @see KPageDialog * @author Thomas Tanghus * @author Espen Sand * @author Mirko Boehm * @author Olivier Goffart * @author Tobias Koenig */ class KRITAWIDGETS_EXPORT KoDialog : public QDialog //krazy:exclude=qclasses { Q_OBJECT Q_ENUMS(ButtonCode) Q_DECLARE_PRIVATE(KoDialog) public: enum ButtonCode { None = 0x00000000, Help = 0x00000001, ///< Show Help button. (this button will run the help set with setHelp) Default = 0x00000002, ///< Show Default button. Ok = 0x00000004, ///< Show Ok button. (this button accept()s the dialog; result set to QDialog::Accepted) Apply = 0x00000008, ///< Show Apply button. Try = 0x00000010, ///< Show Try button. Cancel = 0x00000020, ///< Show Cancel-button. (this button reject()s the dialog; result set to QDialog::Rejected) Close = 0x00000040, ///< Show Close-button. (this button closes the dialog) No = 0x00000080, ///< Show No button. (this button closes the dialog and sets the result to KoDialog::No) Yes = 0x00000100, ///< Show Yes button. (this button closes the dialog and sets the result to KoDialog::Yes) Reset = 0x00000200, ///< Show Reset button Details = 0x00000400, ///< Show Details button. (this button will show the detail widget set with setDetailsWidget) User1 = 0x00001000, ///< Show User defined button 1. User2 = 0x00002000, ///< Show User defined button 2. User3 = 0x00004000, ///< Show User defined button 3. NoDefault = 0x00008000 ///< Used when specifying a default button; indicates that no button should be marked by default. }; // TODO KDE5: remove NoDefault and use the value None instead Q_DECLARE_FLAGS(ButtonCodes, ButtonCode) enum ButtonPopupMode { InstantPopup = 0, DelayedPopup = 1 }; Q_DECLARE_FLAGS(ButtonPopupModes, ButtonPopupMode) public: /** * Creates a dialog. * * @param parent The parent of the dialog. * @param flags The widget flags passed to the QDialog constructor */ explicit KoDialog(QWidget *parent = 0, Qt::WindowFlags flags = 0); /** * Destroys the dialog. */ ~KoDialog() override; /** * Creates (or recreates) the button box and all the buttons in it. * * Note that some combinations are not possible. That means, you can't * have the following pairs of buttons in a dialog: * - Default and Details * - Cancel and Close * - Ok and Try * * This will reset all default KGuiItem of all button. * * @param buttonMask Specifies what buttons will be made. * * @deprecated Since 5.0 use QDialogButtonBox */ void setButtons(ButtonCodes buttonMask); /** * Sets the orientation of the button box. * * It can be @p Vertical or @p Horizontal. If @p Horizontal * (default), the button box is positioned at the bottom of the * dialog. If @p Vertical it will be placed at the right edge of the * dialog. * * @param orientation The button box orientation. */ void setButtonsOrientation(Qt::Orientation orientation); /** * Sets the button that will be activated when the Escape key * is pressed. * * By default, the Escape key is mapped to either the Cancel or the Close button * if one of these buttons are defined. The user expects that Escape will * cancel an operation so use this function with caution. * * @param id The button code. */ void setEscapeButton(ButtonCode id); /** * Sets the button that will be activated when the Enter key * is pressed. * * By default, this is the Ok button if it is present * * @param id The button code. */ void setDefaultButton(ButtonCode id); /** * Returns the button code of the default button, * or NoDefault if there is no default button. */ ButtonCode defaultButton() const; /** * Hide or display the a separator line drawn between the action * buttons an the main widget. */ void showButtonSeparator(bool state); /** * Hide or display a general action button. * * Only buttons that have * been created in the constructor can be displayed. This method will * not create a new button. * * @param id Button identifier. * @param state true display the button(s). */ void showButton(ButtonCode id, bool state); /** * Sets the text of any button. * * @param id The button identifier. * @param text Button text. */ void setButtonText(ButtonCode id, const QString &text); /** * Returns the text of any button. */ QString buttonText(ButtonCode id) const; /** * Sets the icon of any button. * * @param id The button identifier. * @param icon Button icon. */ void setButtonIcon(ButtonCode id, const QIcon &icon); /** * Returns the icon of any button. */ QIcon buttonIcon(ButtonCode id) const; /** * Sets the tooltip text of any button. * * @param id The button identifier. * @param text Button text. */ void setButtonToolTip(ButtonCode id, const QString &text); /** * Returns the tooltip of any button. */ QString buttonToolTip(ButtonCode id) const; /** * Sets the "What's this?" text of any button. * * @param id The button identifier. * @param text Button text. */ void setButtonWhatsThis(ButtonCode id, const QString &text); /** * Returns the "What's this?" text of any button. */ QString buttonWhatsThis(ButtonCode id) const; /** * Sets the KGuiItem directly for the button instead of using 3 methods to * set the text, tooltip and whatsthis strings. This also allows to set an * icon for the button which is otherwise not possible for the extra * buttons beside Ok, Cancel and Apply. * * @param id The button identifier. * @param item The KGuiItem for the button. */ void setButtonGuiItem(ButtonCode id, const KGuiItem &item); /** * Sets the focus to the button of the passed @p id. */ void setButtonFocus(ButtonCode id); /** * Convenience method. Sets the initial dialog size. * * This method should only be called right before show() or exec(). * The initial size will be ignored if smaller than * the dialog's minimum size. * * @param size Startup size. */ void setInitialSize(const QSize &size); /** * Convenience method. Add a size to the default minimum size of a * dialog. * * This method should only be called right before show() or exec(). * * @param size Size added to minimum size. */ void incrementInitialSize(const QSize &size); /** * Returns the help link text. * * If no text has been defined, * "Get help..." (internationalized) is returned. * * @return The help link text. * * @see enableLinkedHelp() * @see setHelpLinkText() * @see setHelp() */ QString helpLinkText() const; /** * Returns whether any button is enabled. */ bool isButtonEnabled(ButtonCode id) const; /** * Returns the button that corresponds to the @p id. * * Normally you should not use this function. * @em Never delete the object returned by this function. * See also enableButton(), showButton(), setButtonGuiItem(). * * @param id Identifier of the button. * @return The button or 0 if the button does not exist. */ QPushButton *button(ButtonCode id) const; /** * Returns the number of pixels that should be used between a * dialog edge and the outermost widget(s) according to the KDE standard. * * @deprecated Use the style's pixelMetric() function to query individual margins. * Different platforms may use different values for the four margins. */ static int marginHint(); /** * Returns the number of pixels that should be used between * widgets inside a dialog according to the KDE standard. * * @deprecated Use the style's layoutSpacing() function to query individual spacings. * Different platforms may use different values depending on widget types and pairs. */ static int spacingHint(); /** * Returns the number of pixels that should be used to visually * separate groups of related options in a dialog according to * the KDE standard. * @since 4.2 */ static int groupSpacingHint(); /** * @enum StandardCaptionFlag * Used to specify how to construct a window caption * - * @value AppName Indicates that the method shall include + * @var AppName Indicates that the method shall include * the application name when making the caption string. - * @value Modified Causes a 'modified' sign will be included in the + * @var Modified Causes a 'modified' sign will be included in the * returned string. This is useful when indicating that a file is * modified, i.e., it contains data that has not been saved. - * @value HIGCompliant The base minimum flags required to align a + * @var HIGCompliant The base minimum flags required to align a * caption with the KDE Human Interface Guidelines */ enum CaptionFlag { NoCaptionFlags = 0, AppNameCaption = 1, ModifiedCaption = 2, HIGCompliantCaption = AppNameCaption }; Q_DECLARE_FLAGS(CaptionFlags, CaptionFlag) /** * Builds a caption that contains the application name along with the * userCaption using a standard layout. * * To make a compliant caption for your window, simply do: * @p setWindowTitle(KoDialog::makeStandardCaption(yourCaption)); * * To ensure that the caption is appropriate to the desktop in which the * application is running, pass in a pointer to the window the caption will * be applied to. * * If using a KoDialog or KMainWindow subclass, call setCaption instead and * an appropriate standard caption will be created for you * * @param userCaption The caption string you want to display in the * window caption area. Do not include the application name! * @param window a pointer to the window this application will apply to * @param flags * @return the created caption */ static QString makeStandardCaption(const QString &userCaption, QWidget *window = 0, CaptionFlags flags = HIGCompliantCaption); /** * Resize every layout manager used in @p widget and its nested children. * * @param widget The widget used. * @param margin The new layout margin. * @param spacing The new layout spacing. * * @deprecated Use QLayout functions where necessary. Setting margin and spacing * values recursively for all children prevents QLayout from creating platform native * layouts. */ static void resizeLayout(QWidget *widget, int margin, int spacing); /** * Resize every layout associated with @p lay and its children. * * @param lay layout to be resized * @param margin The new layout margin * @param spacing The new layout spacing * * @deprecated Use QLayout functions where necessary. Setting margin and spacing * values recursively for all children prevents QLayout from creating platform native * layouts. */ static void resizeLayout(QLayout *lay, int margin, int spacing); /** * Centers @p widget on the desktop, taking multi-head setups into * account. If @p screen is -1, @p widget will be centered on its * current screen (if it was shown already) or on the primary screen. * If @p screen is -3, @p widget will be centered on the screen that * currently contains the mouse pointer. * @p screen will be ignored if a merged display (like Xinerama) is not * in use, or merged display placement is not enabled in kdeglobals. */ static void centerOnScreen(QWidget *widget, int screen = -1); /** * Places @p widget so that it doesn't cover a certain @p area of the screen. * This is typically used by the "find dialog" so that the match it finds can * be read. * For @p screen, see centerOnScreen * @return true on success (widget doesn't cover area anymore, or never did), * false on failure (not enough space found) */ static bool avoidArea(QWidget *widget, const QRect &area, int screen = -1); /** * Sets the main widget of the dialog. */ void setMainWidget(QWidget *widget); /** * @return The current main widget. Will create a QWidget as the mainWidget * if none was set before. This way you can write * \code * ui.setupUi(mainWidget()); * \endcode * when using designer. */ QWidget *mainWidget(); /** * Reimplemented from QDialog. */ QSize sizeHint() const override; /** * Reimplemented from QDialog. */ QSize minimumSizeHint() const override; public Q_SLOTS: /** * Make a KDE compliant caption. * * @param caption Your caption. Do @p not include the application name * in this string. It will be added automatically according to the KDE * standard. * * @deprecated Since 5.0 use QWidget::setWindowTitle */ virtual void setCaption(const QString &caption); /** * Makes a KDE compliant caption. * * @param caption Your caption. @em Do @em not include the application name * in this string. It will be added automatically according to the KDE * standard. * @param modified Specify whether the document is modified. This displays * an additional sign in the title bar, usually "**". * * @deprecated Since 5.0 use QWidget::setWindowTitle and QWidget::setWindowModified. */ virtual void setCaption(const QString &caption, bool modified); /** * Make a plain caption without any modifications. * * @param caption Your caption. This is the string that will be * displayed in the window title. */ virtual void setPlainCaption(const QString &caption); /** * Enable or disable (gray out) a general action button. * * @param id Button identifier. * @param state @p true enables the button(s). */ void enableButton(ButtonCode id, bool state); /** * Enable or disable (gray out) the OK button. * * @param state @p true enables the button. */ void enableButtonOk(bool state); /** * Enable or disable (gray out) the Apply button. * * @param state true enables the button. */ void enableButtonApply(bool state); /** * Enable or disable (gray out) the Cancel button. * * @param state true enables the button. */ void enableButtonCancel(bool state); /** * Display or hide the help link area on the top of the dialog. * * @param state @p true will display the area. * * @see helpLinkText() * @see setHelpLinkText() * @see setHelp() */ void enableLinkedHelp(bool state); /** * Sets the text that is shown as the linked text. * * If text is empty, * the text "Get help..." (internationalized) is used instead. * * @param text The link text. * * @see helpLinkText() * @see enableLinkedHelp() * @see setHelp() */ void setHelpLinkText(const QString &text); /** * Sets the help path and topic. * * @param anchor Defined anchor in your docbook sources * @param appname Defines the appname the help belongs to * If empty it's the current one * * @note The help button works differently for the class * KCMultiDialog, so it does not make sense to call this * function for Dialogs of that type. See * KCMultiDialog::slotHelp() for more information. */ void setHelp(const QString &anchor, const QString &appname = QString()); /** * Returns the status of the Details button. */ bool isDetailsWidgetVisible() const; /** * Sets the status of the Details button. */ void setDetailsWidgetVisible(bool visible); /** * Sets the widget that gets shown when "Details" is enabled. * * The dialog takes over ownership of the widget. * Any previously set widget gets deleted. */ void setDetailsWidget(QWidget *detailsWidget); /** * Destruct the dialog delayed. * * You can call this function from slots like closeClicked() and hidden(). * You should not use the dialog any more after calling this function. * @deprecated use hide()+deleteLater() */ void delayedDestruct(); Q_SIGNALS: /** * Emitted when the margin size and/or spacing size * have changed. * * Use marginHint() and spacingHint() in your slot * to get the new values. * * @deprecated This signal is not emitted. Listen to QEvent::StyleChange events instead. */ void layoutHintChanged(); /** * The Help button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void helpClicked(); /** * The Default button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void defaultClicked(); /** * The Reset button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void resetClicked(); /** * The User3 button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void user3Clicked(); /** * The User2 button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void user2Clicked(); /** * The User1 button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void user1Clicked(); /** * The Apply button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void applyClicked(); /** * The Try button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void tryClicked(); /** * The OK button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void okClicked(); /** * The Yes button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void yesClicked(); /** * The No button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void noClicked(); /** * The Cancel button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void cancelClicked(); /** * The Close button was pressed. This signal is only emitted if * slotButtonClicked() is not replaced */ void closeClicked(); /** * A button has been pressed. This signal is only emitted if * slotButtonClicked() is not replaced * @param button is the code of the pressed button. */ void buttonClicked(KoDialog::ButtonCode button); /** * The dialog is about to be hidden. * * A dialog is hidden after a user clicks a button that ends * the dialog or when the user switches to another desktop or * minimizes the dialog. */ void hidden(); /** * The dialog has finished. * * A dialog emits finished after a user clicks a button that ends * the dialog. * * This signal is also emitted when you call hide() * * If you have stored a pointer to the * dialog do @em not try to delete the pointer in the slot that is * connected to this signal. * * You should use deleteLater() instead. */ void finished(); /** * The detailsWidget is about to get shown. This is your last chance * to call setDetailsWidget if you haven't done so yet. */ void aboutToShowDetails(); protected: /** * Emits the #hidden signal. You can connect to that signal to * detect when a dialog has been closed. */ void hideEvent(QHideEvent *) override; /** * Detects when a dialog is being closed from the window manager * controls. If the Cancel or Close button is present then the button * is activated. Otherwise standard QDialog behavior * will take place. */ void closeEvent(QCloseEvent *e) override; /** * @internal */ void keyPressEvent(QKeyEvent *) override; protected Q_SLOTS: /** * Activated when the button @p button is clicked * * Sample that shows how to catch and handle button clicks within * an own dialog; * @code * class MyDialog : public KoDialog { * protected Q_SLOTS: * virtual void slotButtonClicked(int button) { * if (button == KoDialog::Ok) * accept(); * else * KoDialog::slotButtonClicked(button); * } * } * @endcode * * @param button is the type @a KoDialog::ButtonCode * * @deprecated since 5.0 use QDialogButtonBox and connect to the clicked signal */ virtual void slotButtonClicked(int button); /** * Updates the margins and spacings. * * @deprecated KoDialog respects the style's margins and spacings automatically. Calling * this function has no effect. */ void updateGeometry(); private: KoDialog(KoDialogPrivate &dd, QWidget *parent, Qt::WindowFlags flags = 0); KoDialogPrivate *const d_ptr; private: Q_DISABLE_COPY(KoDialog) Q_PRIVATE_SLOT(d_ptr, void queuedLayoutUpdate()) Q_PRIVATE_SLOT(d_ptr, void helpLinkClicked()) }; Q_DECLARE_OPERATORS_FOR_FLAGS(KoDialog::ButtonCodes) Q_DECLARE_OPERATORS_FOR_FLAGS(KoDialog::CaptionFlags) #endif // KODIALOG_H diff --git a/libs/widgets/KoResourcePopupAction.h b/libs/widgets/KoResourcePopupAction.h index 884e7d59f0..f778d02de7 100644 --- a/libs/widgets/KoResourcePopupAction.h +++ b/libs/widgets/KoResourcePopupAction.h @@ -1,74 +1,75 @@ /* This file is part of the KDE project * Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) * Copyright (C) 2012 Jean-Nicolas Artaud * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KORESOURCEPOPUPACTION_H #define KORESOURCEPOPUPACTION_H #include #include #include class KoShapeBackground; class KoAbstractResourceServerAdapter; class QModelIndex; #include "kritawidgets_export.h" class KRITAWIDGETS_EXPORT KoResourcePopupAction : public QAction { Q_OBJECT public: /** * Constructs a KoResourcePopupAction (gradient or pattern) with the specified parent. * + * @param gradientResourceAdapter pointer to the gradient or pattern * @param parent The parent for this action. */ explicit KoResourcePopupAction(QSharedPointergradientResourceAdapter, QObject *parent = 0); /** * Destructor */ ~KoResourcePopupAction() override; QSharedPointer currentBackground() const; void setCurrentBackground(QSharedPointer background); void setCurrentResource(KoResourceSP resource); KoResourceSP currentResource() const; Q_SIGNALS: /// Emitted when a resource was selected void resourceSelected(QSharedPointer background); public Q_SLOTS: void updateIcon(); private Q_SLOTS: void indexChanged(const QModelIndex &modelIndex); private: class Private; Private * const d; }; #endif /* KORESOURCEPOPUPACTION_H */ diff --git a/libs/widgets/KoResourceServer.h b/libs/widgets/KoResourceServer.h index ddb4554936..019dc40d99 100644 --- a/libs/widgets/KoResourceServer.h +++ b/libs/widgets/KoResourceServer.h @@ -1,676 +1,676 @@ /* This file is part of the KDE project Copyright (c) 1999 Matthias Elter Copyright (c) 2003 Patrick Julien Copyright (c) 2005 Sven Langkamp Copyright (c) 2007 Jan Hambrecht Copyright (C) 2011 Srikanth Tiyyagura Copyright (c) 2013 Sascha Suelzer This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef KORESOURCESERVER_H #define KORESOURCESERVER_H #include #include #include #include #include #include #include #include #include "KoResource.h" #include "KoResourceServerObserver.h" #include "KoResourceTagStore.h" #include "KoResourcePaths.h" #include #include #include #include #include "kritawidgets_export.h" #include "WidgetsDebug.h" class KoResource; /** * KoResourceServerBase is the base class of all resource servers */ class KRITAWIDGETS_EXPORT KoResourceServerBase { public: /** * Constructs a KoResourceServerBase - * @param resource type, has to be the same as used by KoResourcePaths + * @param type type, has to be the same as used by KoResourcePaths * @param extensions the file extensions separate by ':', e.g. *.svg:*.ggr" */ KoResourceServerBase(const QString& type, const QString& extensions) : m_resourceModel(KisResourceModelProvider::resourceModel(type)) , m_type(type) , m_extensions(extensions) { qDebug() << "Creating KoResourceServerBase" << m_type << m_extensions; } virtual ~KoResourceServerBase() {} virtual int resourceCount() const = 0; virtual void loadResources(QStringList filenames) = 0; virtual QStringList blackListedFiles() = 0; virtual QStringList queryResources(const QString &query) const = 0; QString type() const { return m_type; } /** * File extensions for resources of the server * @returns the file extensions separated by ':', e.g. "*.svg:*.ggr" */ QString extensions() const { return m_extensions; } QStringList fileNames() { QStringList extensionList = m_extensions.split(':'); QStringList fileNames; foreach (const QString &extension, extensionList) { fileNames += KoResourcePaths::findAllResources(type().toLatin1(), extension, KoResourcePaths::Recursive); } return fileNames; } protected: KisResourceModel *m_resourceModel {0}; QStringList m_blackListFileNames; friend class KoResourceTagStore; virtual KoResourceSP byMd5(const QByteArray &md5) const = 0; virtual KoResourceSP byFileName(const QString &fileName) const = 0; private: QString m_type; QString m_extensions; protected: QMutex m_loadLock; }; /** * KoResourceServer manages the resources of one type. It stores, * loads and saves the resources. To keep track of changes the server * can be observed with a KoResourceServerObserver */ template class KoResourceServer : public KoResourceServerBase { public: typedef KoResourceServerObserver ObserverType; KoResourceServer(const QString& type, const QString& extensions) : KoResourceServerBase(type, extensions) { m_blackListFile = KoResourcePaths::locateLocal("data", type + ".blacklist"); m_blackListFileNames = readBlackListFile(); m_tagStore = new KoResourceTagStore(this); } ~KoResourceServer() override { if (m_tagStore) { delete m_tagStore; } Q_FOREACH (ObserverType* observer, m_observers) { observer->unsetResourceServer(); } m_resources.clear(); } int resourceCount() const override { return m_resourceModel->rowCount(); } /** * Loads a set of resources and adds them to the resource server. * If a filename appears twice the resource will only be added once. Resources that can't * be loaded or and invalid aren't added to the server. * @param filenames list of filenames to be loaded */ void loadResources(QStringList /*filenames*/) override { } void loadTags() { m_tagStore->loadTags(); } void clearOldSystemTags() { m_tagStore->clearOldSystemTags(); } /// Adds an already loaded resource to the server bool addResource(QSharedPointer resource, bool save = true, bool infront = false) { if (!resource->valid()) { warnWidgets << "Tried to add an invalid resource!"; return false; } if (save) { QFileInfo fileInfo(resource->filename()); QDir d(fileInfo.path()); if (!d.exists()) { d.mkdir(fileInfo.path()); } if (fileInfo.exists()) { QString filename = fileInfo.path() + "/" + fileInfo.baseName() + "XXXXXX" + "." + fileInfo.suffix(); debugWidgets << "fileName is " << filename; QTemporaryFile file(filename); if (file.open()) { debugWidgets << "now " << file.fileName(); resource->setFilename(file.fileName()); } } if (!resource->save()) { warnWidgets << "Could not save resource!"; return false; } } Q_ASSERT(!resource->filename().isEmpty() || !resource->name().isEmpty()); if (resource->filename().isEmpty()) { resource->setFilename(resource->name()); } else if (resource->name().isEmpty()) { resource->setName(resource->filename()); } m_resourcesByFilename[resource->shortFilename()] = resource; addResourceToMd5Registry(resource); m_resourcesByName[resource->name()] = resource; if (infront) { m_resources.insert(0, resource); } else { m_resources.append(resource); } notifyResourceAdded(resource); return true; } /** * Removes a given resource from the blacklist. */ bool removeFromBlacklist(QSharedPointer resource) { if (m_blackListFileNames.contains(resource->filename())) { m_blackListFileNames.removeAll(resource->filename()); writeBlackListFile(); return true; } return false; } /// Remove a resource from Resource Server but not from a file bool removeResourceFromServer(QSharedPointer resource){ if ( !m_resourcesByFilename.contains( resource->shortFilename() ) ) { return false; } removeResourceFromMd5Registry(resource); m_resourcesByName.remove(resource->name()); m_resourcesByFilename.remove(resource->shortFilename()); m_resources.removeAt(m_resources.indexOf(resource)); m_tagStore->removeResource(resource); notifyRemovingResource(resource); return true; } /// Remove a resource from the resourceserver and blacklist it bool removeResourceAndBlacklist(QSharedPointer resource) { if ( !m_resourcesByFilename.contains( resource->shortFilename() ) ) { return false; } removeResourceFromMd5Registry(resource); m_resourcesByName.remove(resource->name()); m_resourcesByFilename.remove(resource->shortFilename()); m_resources.removeAt(m_resources.indexOf(resource)); m_tagStore->removeResource(resource); notifyRemovingResource(resource); m_blackListFileNames.append(resource->filename()); writeBlackListFile(); return true; } QList> resources() { QList> resourceList; for (int row = 0; row < m_resourceModel->rowCount(); ++row) { resourceList << m_resourceModel->resourceForIndex(m_resourceModel->index(row, 0)).dynamicCast(); } return resourceList; } /// Returns path where to save user defined and imported resources to virtual QString saveLocation() { return KoResourcePaths::saveLocation(type().toLatin1()); } /** * Creates a new resource from a given file and adds them to the resource server * The base implementation does only load one resource per file, override to implement collections * @param filename file name of the resource file to be imported * @param fileCreation decides whether to create the file in the saveLocation() directory */ virtual bool importResourceFile(const QString & filename , bool fileCreation=true) { QFileInfo fi(filename); if (!fi.exists()) return false; if ( fi.size() == 0) return false; QSharedPointer resource = createResource( filename ); resource->load(); if (!resource->valid()) { warnWidgets << "Import failed! Resource is not valid"; return false; } if (fileCreation) { Q_ASSERT(!resource->defaultFileExtension().isEmpty()); Q_ASSERT(!saveLocation().isEmpty()); QString newFilename = saveLocation() + fi.baseName() + resource->defaultFileExtension(); QFileInfo fileInfo(newFilename); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(saveLocation() + fi.baseName() + QString("%1").arg(i) + resource->defaultFileExtension()); i++; } resource->setFilename(fileInfo.filePath()); } return true; } /// Removes the resource file from the resource server void removeResourceFile(const QString & filename) { QFileInfo fi(filename); QSharedPointer resource = resourceByFilename(fi.fileName()); if (!resource) { warnWidgets << "Resource file do not exist "; return; } removeResourceFromServer(resource); } /** * Addes an observer to the server * @param observer the observer to be added * @param notifyLoadedResources determines if the observer should be notified about the already loaded resources */ void addObserver(ObserverType* observer, bool notifyLoadedResources = true) { m_loadLock.lock(); if(observer && !m_observers.contains(observer)) { m_observers.append(observer); if(notifyLoadedResources) { Q_FOREACH (QSharedPointer resource, m_resourcesByFilename) { observer->resourceAdded(resource); } } } m_loadLock.unlock(); } /** * Removes an observer from the server * @param observer the observer to be removed */ void removeObserver(ObserverType* observer) { int index = m_observers.indexOf( observer ); if( index < 0 ) return; m_observers.removeAt( index ); } QSharedPointer resourceByFilename(const QString& /*filename*/) const { // if (m_resourcesByFilename.contains(filename)) { // return m_resourcesByFilename[filename]; // } return 0; } QSharedPointer resourceByName( const QString& /*name */) const { // if (m_resourcesByName.contains(name)) { // return m_resourcesByName[name]; // } return 0; } QSharedPointer resourceByMD5(const QByteArray& /*md5*/) const { // return m_resourcesByMd5.value(md5); return 0; } /** * Call after changing the content of a resource; * Notifies the connected views. */ void updateResource(QSharedPointer resource) { notifyResourceChanged(resource); } QStringList blackListedFiles() override { if (type() == "kis_resourcebundles") { KConfigGroup group = KSharedConfig::openConfig()->group("BundleHack"); if (group.readEntry("HideKrita3Bundle", true)) { Q_FOREACH(const QString &filename, fileNames()) { if (filename.endsWith("Krita_3_Default_Resources.bundle")) { if (!m_blackListFileNames.contains(filename)) { m_blackListFileNames.append(filename); } } } } // qDebug() << "blacklisted filenames" << m_blackListFileNames; } return m_blackListFileNames; } void removeBlackListedFiles() { QStringList remainingFiles; // Files that can't be removed e.g. no rights will stay blacklisted Q_FOREACH (const QString &filename, m_blackListFileNames) { QFile file( filename ); if( ! file.remove() ) { remainingFiles.append(filename); } } m_blackListFileNames = remainingFiles; writeBlackListFile(); } QStringList tagNamesList() const { return m_tagStore->tagNamesList(); } // don't use these method directly since it doesn't update views! void addTag(KoResourceSP resource, const QString& tag) { m_tagStore->addTag(resource, tag); } // don't use these method directly since it doesn't update views! void delTag(KoResourceSP resource, const QString& tag) { m_tagStore->delTag(resource, tag); } QStringList searchTag(const QString& lineEditText) { return m_tagStore->searchTag(lineEditText); } void tagCategoryAdded(const QString& tag) { m_tagStore->serializeTags(); Q_FOREACH (ObserverType* observer, m_observers) { observer->syncTagAddition(tag); } } void tagCategoryRemoved(const QString& tag) { m_tagStore->delTag(tag); m_tagStore->serializeTags(); Q_FOREACH (ObserverType* observer, m_observers) { observer->syncTagRemoval(tag); } } void tagCategoryMembersChanged() { m_tagStore->serializeTags(); Q_FOREACH (ObserverType* observer, m_observers) { observer->syncTaggedResourceView(); } } QStringList queryResources(const QString &query) const override { return m_tagStore->searchTag(query); } QStringList assignedTagsList(KoResourceSP resource) const { return m_tagStore->assignedTagsList(resource); } /** * Create one or more resources from a single file. By default one resource is created. * Override to create more resources from the file. * @param filename the filename of the resource or resource collection */ virtual QList> createResources( const QString & filename ) { QList> createdResources; createdResources.append(createResource(filename)); return createdResources; } virtual QSharedPointer createResource( const QString & filename ) = 0; /// Return the currently stored resources in alphabetical order, overwrite for customized sorting virtual QList> sortedResources() { QMap> sortedNames; Q_FOREACH (const QString &name, m_resourcesByName.keys()) { sortedNames.insert(name.toLower(), m_resourcesByName[name]); } return sortedNames.values(); } protected: void notifyResourceAdded(QSharedPointer resource) { Q_FOREACH (ObserverType* observer, m_observers) { observer->resourceAdded(resource); } } void notifyRemovingResource(QSharedPointer resource) { Q_FOREACH (ObserverType* observer, m_observers) { observer->removingResource(resource); } } void notifyResourceChanged(QSharedPointer resource) { Q_FOREACH (ObserverType* observer, m_observers) { observer->resourceChanged(resource); } } /// Reads the xml file and returns the filenames as a list QStringList readBlackListFile() { QStringList filenameList; QFile f(m_blackListFile); if (!f.open(QIODevice::ReadOnly)) { return filenameList; } QDomDocument doc; if (!doc.setContent(&f)) { warnWidgets << "The file could not be parsed."; return filenameList; } QDomElement root = doc.documentElement(); if (root.tagName() != "resourceFilesList") { warnWidgets << "The file doesn't seem to be of interest."; return filenameList; } QDomElement file = root.firstChildElement("file"); while (!file.isNull()) { QDomNode n = file.firstChild(); QDomElement e = n.toElement(); if (e.tagName() == "name") { // If the krita bundle has landed in the blacklist, skip it. if (type() == "kis_resourcebundles") { // qDebug() << "Checking for not reading bundle" << e.text(); if (e.text().endsWith("Krita_3_Default_Resources.bundle")) { file = file.nextSiblingElement("file"); } } filenameList.append(e.text().replace(QString("~"), QDir::homePath())); } file = file.nextSiblingElement("file"); } // if (type() == "kis_resourcebundles") { // qDebug() << "Read bundle blacklist" << filenameList; // } return filenameList; } /// write the blacklist file entries to an xml file void writeBlackListFile() { QFile f(m_blackListFile); if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) { warnWidgets << "Cannot write meta information to '" << m_blackListFile << "'." << endl; return; } QDomDocument doc; QDomElement root; QDomDocument docTemp("m_blackListFile"); doc = docTemp; doc.appendChild(doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"")); root = doc.createElement("resourceFilesList"); doc.appendChild(root); Q_FOREACH (QString filename, m_blackListFileNames) { // Don't write the krita3 bundle to the blacklist, since its location will change // when using the appimate. if (type() == "kis_resourcebundles") { // qDebug() << "Checking for Not writing krita 3 bundle" << filename; if (filename.endsWith("Krita_3_Default_Resources.bundle")) continue; } QDomElement fileEl = doc.createElement("file"); QDomElement nameEl = doc.createElement("name"); QDomText nameText = doc.createTextNode(filename.replace(QDir::homePath(), QString("~"))); nameEl.appendChild(nameText); fileEl.appendChild(nameEl); root.appendChild(fileEl); } QTextStream metastream(&f); metastream << doc.toString(); f.close(); } protected: KoResourceSP byMd5(const QByteArray &/*md5*/) const override { return 0;//Policy::toResourcePointer(resourceByMD5(md5)); } KoResourceSP byFileName(const QString &/*fileName*/) const override { return 0;//Policy::toResourcePointer(resourceByFilename(fileName)); } private: void addResourceToMd5Registry(QSharedPointer resource) { const QByteArray md5 = resource->md5(); if (!md5.isEmpty()) { m_resourcesByMd5.insert(md5, resource); } } void removeResourceFromMd5Registry(QSharedPointer resource) { const QByteArray md5 = resource->md5(); if (!md5.isEmpty()) { m_resourcesByMd5.remove(md5); } } private: QHash> m_resourcesByName; QHash> m_resourcesByFilename; QHash> m_resourcesByMd5; QList> m_resourceBlackList; QList> m_resources; ///< list of resources in order of addition QList m_observers; QString m_blackListFile; KoResourceTagStore* m_tagStore; }; template class KoResourceServerSimpleConstruction : public KoResourceServer { public: KoResourceServerSimpleConstruction(const QString& type, const QString& extensions) : KoResourceServer(type, extensions) { } QSharedPointer createResource( const QString & filename ) override { return QSharedPointer(new T(filename)); } }; #endif // KORESOURCESERVER_H diff --git a/libs/widgets/KoToolBox_p.h b/libs/widgets/KoToolBox_p.h index 7f0527ff3e..3835f0842b 100644 --- a/libs/widgets/KoToolBox_p.h +++ b/libs/widgets/KoToolBox_p.h @@ -1,113 +1,112 @@ /* * Copyright (c) 2005 Boudewijn Rempt * Copyright (c) 2005-2008 Thomas Zander * Copyright (c) 2009 Peter Simonsson * Copyright (c) 2010 Cyrille Berger * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _KO_TOOLBOX_H_ #define _KO_TOOLBOX_H_ #include #include #include #include class KoCanvasController; class KoShapeLayer; class KoToolBoxLayout; /** * KoToolBox is a dock widget that can order tools according to type and * priority. * * The ToolBox is a container for tool buttons which are themselves * divided into sections. * * Adding buttons using addButton() will allow you to show those buttons. You should connect * the button to your handling method yourself. * * The unique property of this toolbox is that it can be shown horizontal as well as vertical, * rotating in a smart way to show the buttons optimally. * @see KoToolManager */ class KoToolBox : public QWidget { Q_OBJECT public: /// constructor explicit KoToolBox(); ~KoToolBox() override; public Q_SLOTS: /** * Using the buttongroup id passed in addButton() you can set the new active button. * If the id does not resolve to a visible button, this call is ignored. * @param canvas the currently active canvas. * @param id an id to identify the button to activate. */ void setActiveTool(KoCanvasController *canvas, int id); /** * Show only the dynamic buttons that have a code from parameter codes. * The toolbox allows buttons to be optionally registered with a visibilityCode. This code * can be passed here and all buttons that have that code are shown. All buttons that * have another visibility code registered are hidden. - * @param canvas the currently active canvas. * @param codes a list of all the codes to show. */ void setButtonsVisible(const QList &codes); /// Set the orientation of the layout to @p orientation void setOrientation(Qt::Orientation orientation); void setFloating(bool v); KoToolBoxLayout *toolBoxLayout() const; private: /** * Add a button to the toolbox. * The buttons should all be added before the first showing since adding will not really add * them to the UI until setup() is called. * * @param toolAction the action of the tool * @see setup() */ void addButton(KoToolAction *toolAction); private Q_SLOTS: void setCurrentLayer(const KoCanvasController *canvas, const KoShapeLayer* newLayer); /// add a tool post-initialization. The tool will also be activated. void toolAdded(KoToolAction *toolAction, KoCanvasController *canvas); /// set the icon size for all the buttons void slotContextIconSize(); protected: void paintEvent(QPaintEvent *event) override; void contextMenuEvent(QContextMenuEvent *event) override; private: class Private; Private * const d; }; #endif // _KO_TOOLBOX_H_ diff --git a/libs/widgets/KoZoomController.h b/libs/widgets/KoZoomController.h index fb38af78b3..f1b7b652e8 100644 --- a/libs/widgets/KoZoomController.h +++ b/libs/widgets/KoZoomController.h @@ -1,202 +1,203 @@ /* This file is part of the KDE project * Copyright (C) 2007 Thomas Zander * Copyright (C) 2007,2012 C. Boemann * Copyright (C) 2007 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOZOOMCONTROLLER_H #define KOZOOMCONTROLLER_H #include "KoZoomAction.h" #include "kritawidgets_export.h" #include #include #include class KoCanvasController; class KoZoomAction; class KoZoomHandler; class KActionCollection; class QSize; /** * This controller class handles zoom levels for any canvas. * * For each KoCanvasController you should have one instance of this * class to go with it. This class then creates a KoZoomAction and * basically handles all zooming for you. * * All you need to do is connect to the setDocumentSize() slot and * keep the controller up-to-date if your on-screen document ever * changes (note that this is in document units, so this is a zoom * independent size). * * If you choose to have zoom modes of 'page' and 'width' you are * required to set the page size using the setPageSize() method. * * Additionally you can connect to the zoomChanged() signal if you * want to store the latest zoom level and mode, for example to * restore the last used one at next restart. * * The specialAspectMode toggle is only a UI element. It does nothing * except emit the aspectModeChanged signal. * */ class KRITAWIDGETS_EXPORT KoZoomController : public QObject { Q_OBJECT public: /** * Constructor. Create one per canvasController. The zoomAction is created in the constructor and will * be available to the passed actionCollection for usage by XMLGui. * @param controller the canvasController * @param zoomHandler the zoom handler (viewconverter with setter methods) * @param actionCollection the action collection where the KoZoomAction is added to + * @param parent the parent QObject */ KoZoomController(KoCanvasController *controller, KoZoomHandler *zoomHandler, KActionCollection *actionCollection, QObject *parent = 0); /// destructor ~KoZoomController() override; /// returns the zoomAction that is maintained by this controller KoZoomAction *zoomAction() const; /** * Alter the current zoom mode which updates the Gui. * @param mode the new mode that will be used to auto-calculate a new zoom-level if needed. */ void setZoomMode(KoZoomMode::Mode mode); /** * @return the current zoom mode. */ KoZoomMode::Mode zoomMode() const; /** * Set the resolution, zoom, the zoom mode for this zoom Controller. * Typically for use just after construction to restore the * persistent data. * * @param mode new zoom mode for the canvas * @param zoom (for ZOOM_CONSTANT zoom mode only) new zoom value for * the canvas * @param resolutionX new X resolution for the document * @param resolutionY new Y resolution for the document * @param stillPoint (for ZOOM_CONSTANT zoom mode only) the point * which will not change its position in widget * during the zooming. It is measured in view * coordinate system *before* zoom. */ void setZoom(KoZoomMode::Mode mode, qreal zoom, qreal resolutionX, qreal resolutionY, const QPointF &stillPoint); /** * Convenience function that changes resolution with * keeping the centering unchanged */ void setZoom(KoZoomMode::Mode mode, qreal zoom, qreal resolutionX, qreal resolutionY); /** * Convenience function that does not touch the resolution of the * document */ void setZoom(KoZoomMode::Mode mode, qreal zoom, const QPointF &stillPoint); /** * Convenience function with @p center always set to the current * center point of the canvas */ void setZoom(KoZoomMode::Mode mode, qreal zoom); /** * Set Aspect Mode button status and begin a chain of signals */ void setAspectMode(bool status); public Q_SLOTS: /** * Set the size of the current page in document coordinates which allows zoom modes that use the pageSize * to update. * @param pageSize the new page size in points */ void setPageSize(const QSizeF &pageSize); /** * Returns the size of the current page in document coordinates * @returns the page size in points */ QSizeF pageSize() const; /** * Set the size of the whole document currently being shown on the canvas. * The document size will be used together with the current zoom level to calculate the size of the * canvas in the canvasController. * @param documentSize the new document size in points * @param recalculateCenter tells canvas controller not to touch * preferredCenterFraction */ void setDocumentSize(const QSizeF &documentSize, bool recalculateCenter = false); /** * Returns the size of the whole document currently being shown on the canvas. * @returns the document size in points */ QSizeF documentSize() const; Q_SIGNALS: /** * This signal is emitted whenever either the zoommode or the zoom level is changed by the user. * the application can use the emitted data for persistency purposes. */ void zoomChanged (KoZoomMode::Mode mode, qreal zoom); /** * emitted when the special aspect mode toggle changes. * @see KoZoomAction::aspectModeChanged() */ void aspectModeChanged (bool aspectModeActivated); /** * Signal is triggered when the user clicks the zoom to selection button. * Nothing else happens except that this signal is emitted. */ void zoomedToSelection(); /** * Signal is triggered when the user clicks the zoom to all button. * Nothing else happens except that this signal is emitted. */ void zoomedToAll(); protected: virtual QSize documentToViewport(const QSizeF &size); private: Q_PRIVATE_SLOT(d, void setAvailableSize()) Q_PRIVATE_SLOT(d, void requestZoomRelative(const qreal, const QPointF&)) Q_PRIVATE_SLOT(d, void setZoom(KoZoomMode::Mode, qreal)) Q_DISABLE_COPY( KoZoomController ) class Private; Private * const d; }; #endif diff --git a/libs/widgets/KoZoomWidget.h b/libs/widgets/KoZoomWidget.h index ee676fdedd..8b88e915fd 100644 --- a/libs/widgets/KoZoomWidget.h +++ b/libs/widgets/KoZoomWidget.h @@ -1,83 +1,83 @@ /* Copyright (C) 2004 Ariya Hidayat Copyright (C) 2006 Peter Simonsson Copyright (C) 2006-2007 C. Boemann Copyright (C) 2014 Sven Langkamp 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 KOZOOMWIDGET_H #define KOZOOMWIDGET_H #include #include "KoZoomAction.h" #include class KoZoomWidget : public QWidget { Q_OBJECT public: KoZoomWidget(QWidget* parent, int maxZoom); ~KoZoomWidget() override; Q_SIGNALS: /** * Signal sliderValueChanged is triggered when the user moves the slider * @param value value of the slider */ void sliderValueChanged(int value); /** * Signal zoomLevelChanged is triggered when the user changes the KoZoomInput combobox widget - * @param value value of the slider + * @param level value of the slider */ void zoomLevelChanged(const QString& level); /** * Signal aspectModeChanged is triggered when the user toggles the widget. * Nothing else happens except that this signal is emitted. * @param status Whether the special aspect mode is on */ void aspectModeChanged( bool status ); /** * Signal is triggered when the user clicks the zoom to selection button. * Nothing else happens except that this signal is emitted. */ void zoomedToSelection(); /** * Signal is triggered when the user clicks the zoom to all button. * Nothing else happens except that this signal is emitted. */ void zoomedToAll(); public Q_SLOTS: void setZoomLevels(const QStringList &values); void setCurrentZoomLevel(const QString &valueString); void setSliderValue(int value); /** * Change status of "Use same aspect as pixels" button */ void setAspectMode(bool status); private: class Private; QScopedPointer const d; }; #endif // KOZOOMWIDGET_H diff --git a/libs/widgets/kis_palette_view.h b/libs/widgets/kis_palette_view.h index 1a74b9ceb1..6b18ea436d 100644 --- a/libs/widgets/kis_palette_view.h +++ b/libs/widgets/kis_palette_view.h @@ -1,134 +1,134 @@ /* * Copyright (c) 2016 Dmitry Kazakov * Copyright (c) 2017 Wolthera van Hövell tot Westerflier * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 __KIS_PALETTE_VIEW_H #define __KIS_PALETTE_VIEW_H #include #include #include #include #include #include #include #include "kritawidgets_export.h" #include class KisPaletteModel; class QWheelEvent; class KoColorDisplayRendererInterface; class KRITAWIDGETS_EXPORT KisPaletteView : public QTableView { Q_OBJECT private: static int MININUM_ROW_HEIGHT; public: explicit KisPaletteView(QWidget *parent = Q_NULLPTR); ~KisPaletteView() override; void setPaletteModel(KisPaletteModel *model); KisPaletteModel* paletteModel() const; public: /** * @brief setAllowModification * Set whether doubleclick calls up a modification window. This is to prevent users from editing * the palette when the palette is intended to be a list of items. */ void setAllowModification(bool allow); void setDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer); /** * @brief setCrossedKeyword * this apparently allows you to set keywords that can cross out colors. * This is implemented to mark the lazybrush "transparent" color. * @param value */ void setCrossedKeyword(const QString &value); void removeSelectedEntry(); /** * @brief selectClosestColor * select a color that's closest to parameter color * @param color */ void selectClosestColor(const KoColor &color); /** * add an entry with a dialog window. * @warning deprecated. - * kept for compatibility with @ref PaletteView in @ref libkis + * kept for compatibility with PaletteView in libkis */ bool addEntryWithDialog(KoColor color); /** * remove entry with a dialog window.(Necessary for groups. * @warning deprecated. - * kept for compatibility with @ref PaletteView in @ref libkis + * kept for compatibility with PaletteView in libkis */ bool removeEntryWithDialog(QModelIndex index); /** * add entry with a dialog window. * @warning deprecated. - * kept for compatibility with @ref PaletteView in @ref libkis + * kept for compatibility with PaletteView in libkis */ bool addGroupWithDialog(); Q_SIGNALS: void sigIndexSelected(const QModelIndex &index); void sigColorSelected(const KoColor &); public Q_SLOTS: /** * This tries to select the closest color in the palette. * This doesn't update the foreground color, just the visual selection. */ void slotFGColorChanged(const KoColor &); /** * @brief slot that reacts to color changes in resource manager * @param color */ void slotFGColorResourceChanged(const KoColor& color); /** * Slot that selects the right index for provided color. * Called from KisPaletteComboBox when user selects color in the dropdown. */ void slotSelectColor(const KoColor& color); void slotScrollerStateChanged(QScroller::State state){KisKineticScroller::updateCursor(this, state);} private Q_SLOTS: void slotHorizontalHeaderResized(int, int, int newSize); void slotAdditionalGuiUpdate(); void slotCurrentSelectionChanged(const QModelIndex &newCurrent); private: void resizeRows(int newSize); private: struct Private; const QScopedPointer m_d; }; #endif /* __KIS_PALETTE_VIEW_H */ diff --git a/libs/widgets/squeezedcombobox.h b/libs/widgets/squeezedcombobox.h index beaa3934f4..d7b6c4c947 100644 --- a/libs/widgets/squeezedcombobox.h +++ b/libs/widgets/squeezedcombobox.h @@ -1,158 +1,162 @@ /* ============================================================ * Author: Tom Albers * Date : 2005-01-01 * Description : * * Copyright 2005 by Tom Albers * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, 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. * * ============================================================ */ /** @file squeezedcombobox.h */ #ifndef SQUEEZEDCOMBOBOX_H #define SQUEEZEDCOMBOBOX_H class QTimer; class QResizeEvent; class QWidget; // Qt includes. #include #include #include #include "kritawidgets_export.h" /** @class SqueezedComboBox * * This widget is a QComboBox, but then a little bit * different. It only shows the right part of the items * depending on de size of the widget. When it is not * possible to show the complete item, it will be shortened * and "..." will be prepended. * * @image html squeezedcombobox.png "This is how it looks" * @author Tom Albers */ class KRITAWIDGETS_EXPORT SqueezedComboBox : public QComboBox { Q_OBJECT public: /** * Constructor * @param parent parent widget * @param name name to give to the widget */ SqueezedComboBox(QWidget *parent = 0, const char *name = 0); /** * destructor */ ~SqueezedComboBox() override; /** * * Returns true if the combobox contains the original (not-squeezed) * version of text. * @param text the original (not-squeezed) text to check for */ bool contains(const QString & text) const; /** - * Returns index of a orinal text, -1 if the text isn't found + * Returns index of a original text, -1 if the text isn't found * @param text the original (not-squeezed) text to search for */ qint32 findOriginalText(const QString & text) const; /** * Return the list of original text items */ QStringList originalTexts() const; /** * Reset the combo box and initialize it with the list of (original) text items */ void resetOriginalTexts(const QStringList &texts); /** * This inserts a item to the list. See QComboBox::insertItem() - * for detaills. Please do not use QComboBox::insertItem() to this + * for details. Please do not use QComboBox::insertItem() to this * widget, as that will fail. * @param newItem the original (long version) of the item which needs * to be added to the combobox * @param index the position in the widget. + * @param userData the user data. */ void insertSqueezedItem(const QString& newItem, int index, QVariant userData = QVariant()); void insertSqueezedItem(const QIcon &icon, const QString& newItem, int index, QVariant userData = QVariant()); /** * Append an item. * @param newItem the original (long version) of the item which needs * to be added to the combobox + * @param userData the user data. */ void addSqueezedItem(const QString& newItem, QVariant userData = QVariant()); /** * Append an item. + * @param icon the item icon * @param newItem the original (long version) of the item which needs * to be added to the combobox + * @param userData the user data */ void addSqueezedItem(const QIcon &icon, const QString& newItem, QVariant userData = QVariant()); /** * Set the current item to the one matching the given text. * * @param itemText the original (long version) of the item text */ void setCurrent(const QString& itemText); /** * This method returns the full text (not squeezed) of the currently * highlighted item. * @return full text of the highlighted item */ QString itemHighlighted(); /** * remove the squeezed item at index */ void removeSqueezedItem(int index); /** * Sets the sizeHint() of this widget. */ QSize sizeHint() const override; static QString squeezeText(const QString& original, const QWidget *widget); private Q_SLOTS: void slotTimeOut(); private: void resizeEvent(QResizeEvent *) override; // Prevent these from being used. void setCurrentText(const QString& itemText); void insertItem(const QString &text); void insertItem(qint32 index, const QString &text); void addItem(const QString &text); QMap m_originalItems; QTimer *m_timer; }; #endif // SQUEEZEDCOMBOBOX_H diff --git a/libs/widgetutils/config/kcolorscheme.h b/libs/widgetutils/config/kcolorscheme.h index e877b58b6a..dd240b9e0c 100644 --- a/libs/widgetutils/config/kcolorscheme.h +++ b/libs/widgetutils/config/kcolorscheme.h @@ -1,566 +1,570 @@ /* This file is part of the KDE project * Copyright (C) 2007 Matthew Woehlke * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KCOLORSCHEME_H #define KCOLORSCHEME_H #include #include #include #include class QColor; class QBrush; class KColorSchemePrivate; /** * A set of methods used to work with colors. * * KColorScheme currently provides access to the system color palette that the * user has selected (in the future, it is expected to do more). It greatly * expands on QPalette by providing five distinct "sets" with several color * choices each, covering background, foreground, and decoration colors. * * A KColorScheme instance represents colors corresponding to a "set", where a * set consists of those colors used to draw a particular type of element, such * as a menu, button, view, selected text, or tooltip. Each set has a distinct * set of colors, so you should always use the correct set for drawing and * never assume that a particular foreground for one set is the same as the * foreground for any other set. Individual colors may be quickly referenced by * creating an anonymous instance and invoking a lookup member. * * @note * The color palettes for the various states of a widget (active, inactive, * disabled) may be wildly different. Therefore, it is important to take the * state into account. This is why the KColorScheme constructor requires a * QPalette::ColorGroup as an argument. * * To facilitate working with potentially-varying states, two convenience API's * are provided. These are KColorScheme::adjustBackground and its sister * KColorScheme::adjustForeground, and the helper class ::KStatefulBrush. * * @see KColorScheme::ColorSet, KColorScheme::ForegroundRole, * KColorScheme::BackgroundRole, KColorScheme::DecorationRole, * KColorScheme::ShadeRole */ class KRITAWIDGETUTILS_EXPORT KColorScheme { public: /** * This enumeration describes the color set for which a color is being * selected. * * Color sets define a color "environment", suitable for drawing all parts * of a given region. Colors from different sets should not be combined. */ enum ColorSet { /** * Views; for example, frames, input fields, etc. * * If it contains things that can be selected, it is probably a View. */ View, /** * Non-editable window elements; for example, menus. * * If it isn't a Button, View, or Tooltip, it is probably a Window. */ Window, /** * Buttons and button-like controls. * * In addition to buttons, "button-like" controls such as non-editable * dropdowns, scrollbar sliders, slider handles, etc. should also use * this role. */ Button, /** * Selected items in views. * * Note that unfocused or disabled selections should use the Window * role. This makes it more obvious to the user that the view * containing the selection does not have input focus. */ Selection, /** * Tooltips. * * The tooltip set can often be substituted for the view * set when editing is not possible, but the Window set is deemed * inappropriate. "What's This" help is an excellent example, another * might be pop-up notifications (depending on taste). */ Tooltip }; /** * This enumeration describes the background color being selected from the * given set. * * Background colors are suitable for drawing under text, and should never * be used to draw text. In combination with one of the overloads of * KColorScheme::shade, they may be used to generate colors for drawing * frames, bevels, and similar decorations. */ enum BackgroundRole { /** * Normal background. */ NormalBackground = 0, /** * Alternate background; for example, for use in lists. * * This color may be the same as BackgroundNormal, especially in sets * other than View and Window. */ AlternateBackground = 1, /** * Third color; for example, items which are new, active, requesting * attention, etc. * * Alerting the user that a certain field must be filled out would be a * good usage (although NegativeBackground could be used to the same * effect, depending on what you are trying to achieve). Unlike * ActiveText, this should not be used for mouseover effects. */ ActiveBackground = 2, /** * Fourth color; corresponds to (unvisited) links. * * Exactly what this might be used for is somewhat harder to qualify; * it might be used for bookmarks, as a 'you can click here' indicator, * or to highlight recent content (i.e. in a most-recently-accessed * list). */ LinkBackground = 3, /** * Fifth color; corresponds to visited links. * * This can also be used to indicate "not recent" content, especially * when a color is needed to denote content which is "old" or * "archival". */ VisitedBackground = 4, /** * Sixth color; for example, errors, untrusted content, etc. */ NegativeBackground = 5, /** * Seventh color; for example, warnings, secure/encrypted content. */ NeutralBackground = 6, /** * Eighth color; for example, success messages, trusted content. */ PositiveBackground = 7 }; /** * This enumeration describes the foreground color being selected from the * given set. * * Foreground colors are suitable for drawing text or glyphs (such as the * symbols on window decoration buttons, assuming a suitable background * brush is used), and should never be used to draw backgrounds. * * For window decorations, the following is suggested, but not set in * stone: * @li Maximize - PositiveText * @li Minimize - NeutralText * @li Close - NegativeText * @li WhatsThis - LinkText * @li Sticky - ActiveText */ enum ForegroundRole { /** * Normal foreground. */ NormalText = 0, /** * Second color; for example, comments, items which are old, inactive * or disabled. Generally used for things that are meant to be "less * important". InactiveText is not the same role as NormalText in the * inactive state. */ InactiveText = 1, /** * Third color; for example items which are new, active, requesting * attention, etc. May be used as a hover color for clickable items. */ ActiveText = 2, /** * Fourth color; use for (unvisited) links. May also be used for other * clickable items or content that indicates relationships, items that * indicate somewhere the user can visit, etc. */ LinkText = 3, /** * Fifth color; used for (visited) links. As with LinkText, may be used * for items that have already been "visited" or accessed. May also be * used to indicate "historical" (i.e. "old") items or information, * especially if InactiveText is being used in the same context to * express something different. */ VisitedText = 4, /** * Sixth color; for example, errors, untrusted content, deletions, * etc. */ NegativeText = 5, /** * Seventh color; for example, warnings, secure/encrypted content. */ NeutralText = 6, /** * Eighth color; for example, additions, success messages, trusted * content. */ PositiveText = 7 }; /** * This enumeration describes the decoration color being selected from the * given set. * * Decoration colors are used to draw decorations (such as frames) for * special purposes. Like color shades, they are neither foreground nor * background colors. Text should not be painted over a decoration color, * and decoration colors should not be used to draw text. */ enum DecorationRole { /** * Color used to draw decorations for items which have input focus. */ FocusColor, /** * Color used to draw decorations for items which will be activated by * clicking. */ HoverColor }; /** * This enumeration describes the color shade being selected from the given * set. * * Color shades are used to draw "3d" elements, such as frames and bevels. * They are neither foreground nor background colors. Text should not be * painted over a shade, and shades should not be used to draw text. */ enum ShadeRole { /** * The light color is lighter than dark() or shadow() and contrasts * with the base color. */ LightShade, /** * The midlight color is in between base() and light(). */ MidlightShade, /** * The mid color is in between base() and dark(). */ MidShade, /** * The dark color is in between mid() and shadow(). */ DarkShade, /** * The shadow color is darker than light() or midlight() and contrasts * the base color. */ ShadowShade }; /** Construct a copy of another KColorScheme. */ KColorScheme(const KColorScheme &); /** Destructor */ virtual ~KColorScheme(); /** Standard assignment operator */ KColorScheme &operator=(const KColorScheme &); /** * Construct a palette from given color set and state, using the colors * from the given KConfig (if null, the system colors are used). * * @note KColorScheme provides direct access to the color scheme for users * that deal directly with widget states. Unless you are a low-level user * or have a legitimate reason to only care about a fixed, limited number * of states (e.g. windows that cannot be inactive), consider using a * ::KStatefulBrush instead. */ explicit KColorScheme(QPalette::ColorGroup, ColorSet = View, KSharedConfigPtr = KSharedConfigPtr()); /** * Retrieve the requested background brush. */ QBrush background(BackgroundRole = NormalBackground) const; /** * Retrieve the requested foreground brush. */ QBrush foreground(ForegroundRole = NormalText) const; /** * Retrieve the requested decoration brush. */ QBrush decoration(DecorationRole) const; /** * Retrieve the requested shade color, using * KColorScheme::background(KColorScheme::NormalBackground) * as the base color and the contrast setting from the KConfig used to * create this KColorScheme instance (the system contrast setting, if no * KConfig was specified). * * @note Shades are chosen such that all shades would contrast with the * base color. This means that if base is very dark, the 'dark' shades will * be lighter than the base color, with midlight() == shadow(). * Conversely, if the base color is very light, the 'light' shades will be * darker than the base color, with light() == mid(). */ QColor shade(ShadeRole) const; /** * Returns the contrast for borders. * @return the contrast (between 0 for minimum and 10 for maximum * contrast) */ static int contrast(); /** * Returns the contrast for borders as a floating point value. * @param config pointer to the config from which to read the contrast * setting (the default is to use KSharedConfig::openConfig()) * @return the contrast (between 0.0 for minimum and 1.0 for maximum * contrast) */ static qreal contrastF(const KSharedConfigPtr &config = KSharedConfigPtr()); /** * Retrieve the requested shade color, using the specified color as the * base color and the system contrast setting. * * @note Shades are chosen such that all shades would contrast with the * base color. This means that if base is very dark, the 'dark' shades will * be lighter than the base color, with midlight() == shadow(). * Conversely, if the base color is very light, the 'light' shades will be * darker than the base color, with light() == mid(). */ static QColor shade(const QColor &, ShadeRole); /** * Retrieve the requested shade color, using the specified color as the * base color and the specified contrast. * + * @param color the shade color + * @param role the shade role * @param contrast Amount roughly specifying the contrast by which to * adjust the base color, between -1.0 and 1.0 (values between 0.0 and 1.0 * correspond to the value from KColorScheme::contrastF) * @param chromaAdjust (optional) Amount by which to adjust the chroma of * the shade (1.0 means no adjustment) * * @note Shades are chosen such that all shades would contrast with the * base color. This means that if base is very dark, the 'dark' shades will * be lighter than the base color, with midlight() == shadow(). * Conversely, if the base color is very light, the 'light' shades will be * darker than the base color, with light() == mid(). * * @see KColorUtils::shade */ static QColor shade(const QColor &, ShadeRole, qreal contrast, qreal chromaAdjust = 0.0); /** * Adjust a QPalette by replacing the specified QPalette::ColorRole with * the requested background color for all states. Using this method is * safer than replacing individual states, as it insulates you against * changes in QPalette::ColorGroup. * * @note Although it is possible to replace a foreground color using this * method, it's bad usability to do so. Just say "no". */ static void adjustBackground(QPalette &, BackgroundRole newRole = NormalBackground, QPalette::ColorRole color = QPalette::Base, ColorSet set = View, KSharedConfigPtr = KSharedConfigPtr()); /** * Adjust a QPalette by replacing the specified QPalette::ColorRole with * the requested foreground color for all states. Using this method is * safer than replacing individual states, as it insulates you against * changes in QPalette::ColorGroup. * * @note Although it is possible to replace a background color using this * method, it's bad usability to do so. Just say "no". */ static void adjustForeground(QPalette &, ForegroundRole newRole = NormalText, QPalette::ColorRole color = QPalette::Text, ColorSet set = View, KSharedConfigPtr = KSharedConfigPtr()); /** * Used to obtain the QPalette that will be used to set the application * palette from KDE Platform theme. * * @param config KConfig from which to load the colors * * @returns the QPalette * * @since 5.0 */ static QPalette createApplicationPalette(const KSharedConfigPtr &config); private: QExplicitlySharedDataPointer d; }; /** * A container for a "state-aware" brush. * * KStatefulBrush provides an easy and safe way to store a color for use in a * user interface. It is "safe" both in that it will make it easy to deal with * widget states in a correct manner, and that it insulates you against changes * in QPalette::ColorGroup. * * Basically, a stateful brush is used to cache a particular "color" from the * KDE system palette (usually, one which does not live in QPalette). When you * are ready to draw using the brush, you use the current state to retrieve the * appropriate brush. * * Stateful brushes can also be used to apply state effects to arbitrary * brushes, for example when working with a application specific user-defined * color palette. * * @note As of Qt 4.3, QPalette::ColorGroup is missing a state for disabled * widgets in an inactive window. Hopefully Trolltech will fix this bug, at * which point KColorScheme and KStatefulBrush will be updated to recognize the * new state. Using KStatefulBrush will allow your application to inherit these * changes "for free", without even recompiling. */ class KRITAWIDGETUTILS_EXPORT KStatefulBrush { public: /** * Construct a "default" stateful brush. For such an instance, all * overloads of KStatefulBrush::brush will return a default brush (i.e. * QBrush()). */ explicit KStatefulBrush(); /** * Construct a stateful brush from given color set and foreground role, * using the colors from the given KConfig (if null, the system colors are * used). */ explicit KStatefulBrush(KColorScheme::ColorSet, KColorScheme::ForegroundRole, KSharedConfigPtr = KSharedConfigPtr()); /** * Construct a stateful brush from given color set and background role, * using the colors from the given KConfig (if null, the system colors are * used). */ explicit KStatefulBrush(KColorScheme::ColorSet, KColorScheme::BackgroundRole, KSharedConfigPtr = KSharedConfigPtr()); /** * Construct a stateful brush from given color set and decoration role, * using the colors from the given KConfig (if null, the system colors are * used). */ explicit KStatefulBrush(KColorScheme::ColorSet, KColorScheme::DecorationRole, KSharedConfigPtr = KSharedConfigPtr()); /** * Construct a stateful background brush from a specified QBrush (or * QColor, via QBrush's implicit constructor). The various states are * determined from the base QBrush (which fills in the Active state) * according to the same rules used to build stateful color schemes from * the system color scheme. The state effects from the given KConfig are * used (if null, the system state effects are used). */ explicit KStatefulBrush(const QBrush &, KSharedConfigPtr = KSharedConfigPtr()); /** * Construct a stateful foreground/decoration brush from a specified * QBrush (or QColor, via QBrush's implicit constructor). The various * states are determined from the base QBrush (which fills in the Active * state) according to the same rules used to build stateful color schemes * from the system color scheme. The state effects from the given KConfig * are used (if null, the system state effects are used). * + * @param brush The foreground brush * @param background The background brush (or color) corresponding to the * KColorScheme::NormalBackground role and QPalette::Active state for this * foreground/decoration color. + * @param config The configuration. */ explicit KStatefulBrush(const QBrush &, const QBrush &background, KSharedConfigPtr = KSharedConfigPtr()); /** Construct a copy of another KStatefulBrush. */ KStatefulBrush(const KStatefulBrush &); /** Destructor */ ~KStatefulBrush(); /** Standard assignment operator */ KStatefulBrush &operator=(const KStatefulBrush &); /** * Retrieve the brush for the specified widget state. This is used when you * know explicitly what state is wanted. Otherwise one of overloads is * often more convenient. */ QBrush brush(QPalette::ColorGroup) const; /** * Retrieve the brush, using a QPalette reference to determine the correct * state. Use when your painting code has easy access to the QPalette that * it is supposed to be using. The state used in this instance is the * currentColorGroup of the palette. */ QBrush brush(const QPalette &) const; /** * Retrieve the brush, using a QWidget pointer to determine the correct * state. Use when you have a pointer to the widget that you are painting. * The state used is the current state of the widget. * * @note If you pass an invalid widget, you will get a default brush (i.e. * QBrush()). */ QBrush brush(const QWidget *) const; private: class KStatefulBrushPrivate *d; }; Q_DECLARE_METATYPE(KStatefulBrush) /* so we can pass it in QVariant's */ #endif // KCOLORSCHEME_H diff --git a/libs/widgetutils/config/kcolorschememanager.h b/libs/widgetutils/config/kcolorschememanager.h index 71fde0ca6e..20c2bbd17e 100644 --- a/libs/widgetutils/config/kcolorschememanager.h +++ b/libs/widgetutils/config/kcolorschememanager.h @@ -1,121 +1,121 @@ /* This file is part of the KDE project * Copyright (C) 2013 Martin Gräßlin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KCOLORSCHEMEMANAGER_H #define KCOLORSCHEMEMANAGER_H #include #include class QAbstractItemModel; class KActionMenu; class KColorSchemeManagerPrivate; /** * A small helper to get access to all available color schemes and activating a scheme in the * QApplication. This is useful for applications which want to provide a selection of custom color * schemes to their user. For example it is very common for photo and painting applications to use * a dark color scheme even if the default is a light scheme. * * The KColorSchemeManager provides access to a QAbstractItemModel which holds all the available * schemes. A possible usage looks like the following: * * @code * KColorSchemeManager *schemes = new KColorSchemeManager(this); * QListView *view = new QListView(this); * view->setModel(schemes->model()); * connect(view, &QListView::activated, schemes, &KColorSchemeManager::activateScheme); * @endcode * * In addition the KColorSchemeManager also provides the possibility to create a KActionMenu populated * with all the available color schemes in an action group. If one of the actions is selected the * scheme is applied instantly: * * @code * QToolButton *button = new QToolButton(); * KColorSchemeManager *schemes = new KColorSchemeManager(this); * KActionMenu *menu = schemes->createSchemeSelectionMenu(QStringLiteral("Oxygen"), button); * button->setMenu(menu->menu()); * @endcode * * @since 5.0 */ class KRITAWIDGETUTILS_EXPORT KColorSchemeManager : public QObject { Q_OBJECT public: explicit KColorSchemeManager(QObject *parent = 0); ~KColorSchemeManager() override; /** * A QAbstractItemModel of all available color schemes. * * The model provides the name of the scheme in Qt::DisplayRole, a preview * in Qt::DelegateRole and the full path to the scheme file in Qt::UserRole. * * @return Model of all available color schemes. */ QAbstractItemModel *model() const; /** * Returns the model index for the scheme with the given @p name. If no such * scheme exists an invalid index is returned. * @see model */ QModelIndex indexForScheme(const QString &name) const; /** * Creates a KActionMenu populated with all the available color schemes. * All actions are in an action group and when one of the actions is triggered the scheme * referenced by this action is activated. * * The color scheme with the same name as @p selectedSchemeName will be checked. If none * of the available color schemes has the same name, no action will be checked. * * The KActionMenu will not be updated in case the installed color schemes change. It's the * task of the user of the KActionMenu to monitor for changes if required. * * @param icon The icon to use for the KActionMenu * @param text The text to use for the KActionMenu * @param selectedSchemeName The name of the color scheme to select * @param parent The parent of the KActionMenu * @return KActionMenu populated with all available color schemes. * @see activateScheme */ KActionMenu *createSchemeSelectionMenu(const QIcon &icon, const QString &text, const QString &selectedSchemeName, QObject *parent); KActionMenu *createSchemeSelectionMenu(const QString &text, const QString &selectedSchemeName, QObject *parent); KActionMenu *createSchemeSelectionMenu(const QString &selectedSchemeName, QObject *parent); public Q_SLOTS: /** * @brief Activates the KColorScheme identified by the provided @p index. * * Installs the KColorScheme as the QApplication's QPalette. * * @param index The index for the KColorScheme to activate. - * The index must reference the QAbstractItemModel provided by @link model - * @see model() + * The index must reference the QAbstractItemModel provided by @c model + * @see model */ void activateScheme(const QModelIndex &index); private: QScopedPointer d; }; #endif diff --git a/libs/widgetutils/config/kstandardaction.h b/libs/widgetutils/config/kstandardaction.h index e9c5609a10..9055e1614b 100644 --- a/libs/widgetutils/config/kstandardaction.h +++ b/libs/widgetutils/config/kstandardaction.h @@ -1,598 +1,598 @@ /* This file is part of the KDE libraries Copyright (C) 1999,2000 Kurt Granroth Copyright (C) 2001,2002 Ellis Whitehead 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 KSTANDARDACTION_H #define KSTANDARDACTION_H #include #include #include class QObject; class QStringList; class QWidget; class QAction; class KRecentFilesAction; class KDualAction; class KToggleAction; class KToggleFullScreenAction; /** * Convenience methods to access all standard KDE actions. * * These actions should be used instead of hardcoding menubar and * toolbar items. Using these actions helps your application easily * conform to the KDE UI Style Guide * @see http://developer.kde.org/documentation/standards/kde/style/basics/index.html . * * All of the documentation for QAction holds for KStandardAction * also. When in doubt on how things work, check the QAction * documentation first. * Please note that calling any of these methods automatically adds the action * to the actionCollection() of the QObject given by the 'parent' parameter. * * Simple Example:\n * * In general, using standard actions should be a drop in replacement * for regular actions. For example, if you previously had: * * \code * QAction *newAct = new QAction(i18n("&New"), KisIconUtils::loadIcon("document-new"), * KStandardShortcut::shortcut(KStandardShortcut::New), this, * SLOT(fileNew()), actionCollection()); * \endcode * * You could drop that and replace it with: * * \code * QAction *newAct = KStandardAction::openNew(this, SLOT(fileNew()), * actionCollection()); * \endcode * * Non-standard Usages\n * * It is possible to use the standard actions in various * non-recommended ways. Say, for instance, you wanted to have a * standard action (with the associated correct text and icon and * accelerator, etc) but you didn't want it to go in the standard * place (this is not recommended, by the way). One way to do this is * to simply not use the XML UI framework and plug it into wherever * you want. If you do want to use the XML UI framework (good!), then * it is still possible. * * Basically, the XML building code matches names in the XML code with * the internal names of the actions. You can find out the internal * names of each of the standard actions by using the name * method like so: KStandardAction::name(KStandardAction::Cut) would return * 'edit_cut'. The XML building code will match 'edit_cut' to the * attribute in the global XML file and place your action there. * * However, you can change the internal name. In this example, just * do something like: * * \code * (void)KStandardAction::cut(this, SLOT(editCut()), actionCollection(), "my_cut"); * \endcode * * Now, in your local XML resource file (e.g., yourappui.rc), simply * put 'my_cut' where you want it to go. * * Another non-standard usage concerns getting a pointer to an * existing action if, say, you want to enable or disable the action. * You could do it the recommended way and just grab a pointer when * you instantiate it as in the 'openNew' example above... or you * could do it the hard way: * * \code * QAction *cut = actionCollection()->action(KStandardAction::name(KStandardAction::Cut)); * \endcode * * Another non-standard usage concerns instantiating the action in the * first place. Usually, you would use the member functions as * shown above (e.g., KStandardAction::cut(this, SLOT, parent)). You * may, however, do this using the enums provided. This author can't * think of a reason why you would want to, but, hey, if you do, * here's how: * * \code * (void)KStandardAction::action(KStandardAction::New, this, SLOT(fileNew()), actionCollection()); * (void)KStandardAction::action(KStandardAction::Cut, this, SLOT(editCut()), actionCollection()); * \endcode * * @author Kurt Granroth */ namespace KStandardAction { /** * The standard menubar and toolbar actions. */ enum StandardAction { ActionNone, // File Menu New, Open, OpenRecent, Save, SaveAs, Revert, Close, Print, PrintPreview, Mail, Quit, // Edit Menu Undo, Redo, Cut, Copy, Paste, SelectAll, Deselect, Find, FindNext, FindPrev, Replace, // View Menu ActualSize, FitToPage, FitToWidth, FitToHeight, ZoomIn, ZoomOut, Zoom, Redisplay, // Go Menu Up, Back, Forward, Home /*Home page*/, Prior, Next, Goto, GotoPage, GotoLine, FirstPage, LastPage, DocumentBack, DocumentForward, // Bookmarks Menu AddBookmark, EditBookmarks, // Tools Menu Spelling, // Settings Menu ShowMenubar, ShowToolbar, ShowStatusbar, SaveOptions, KeyBindings, Preferences, ConfigureToolbars, // Help Menu Help, HelpContents, WhatsThis, ReportBug, AboutApp, AboutKDE, TipofDay, // Other standard actions ConfigureNotifications, FullScreen, Clear, PasteText, SwitchApplicationLanguage }; /** * Creates an action corresponding to one of the * KStandardAction::StandardAction actions, which is connected to the given * object and @p slot, and is owned by @p parent. * * The signal that is connected to @p slot is triggered(bool), except for the case of * OpenRecent standard action, which uses the urlSelected(const QUrl &) signal of * KRecentFilesAction. * * @param id The StandardAction identifier to create a QAction for. * @param recvr The QObject to receive the signal, or 0 if no notification * is needed. * @param slot The slot to connect the signal to (remember to use the SLOT() macro). * @param parent The QObject that should own the created QAction, or 0 if no parent will * own the QAction returned (ensure you delete it manually in this case). */ KRITAWIDGETUTILS_EXPORT QAction *create(StandardAction id, const QObject *recvr, const char *slot, QObject *parent); /** * This will return the internal name of a given standard action. */ KRITAWIDGETUTILS_EXPORT const char *name(StandardAction id); /// @deprecated use name() #ifndef KDE_NO_DEPRECATED inline KRITAWIDGETUTILS_DEPRECATED const char *stdName(StandardAction act_enum) { return name(act_enum); } #endif /** * Returns a list of all standard names. Used by KAccelManager * to give those higher weight. */ KRITAWIDGETUTILS_EXPORT QStringList stdNames(); /** * Returns a list of all actionIds. * * @since 4.2 */ KRITAWIDGETUTILS_EXPORT QList actionIds(); /** * Returns the standardshortcut associated with @a actionId. * - * @param actionId The actionId whose associated shortcut is wanted. + * @param id The actionId whose associated shortcut is wanted. * * @since 4.2 */ KRITAWIDGETUTILS_EXPORT KStandardShortcut::StandardShortcut shortcutForActionId(StandardAction id); /** * Create a new document or window. */ KRITAWIDGETUTILS_EXPORT QAction *openNew(const QObject *recvr, const char *slot, QObject *parent); /** * Open an existing file. */ KRITAWIDGETUTILS_EXPORT QAction *open(const QObject *recvr, const char *slot, QObject *parent); /** * Open a recently used document. The signature of the slot being called * is of the form slotURLSelected( const QUrl & ). * @param recvr object to receive slot * @param slot The SLOT to invoke when a URL is selected. The slot's * signature is slotURLSelected( const QUrl & ). * @param parent parent widget */ KRITAWIDGETUTILS_EXPORT KRecentFilesAction *openRecent(const QObject *recvr, const char *slot, QObject *parent); /** * Save the current document. */ KRITAWIDGETUTILS_EXPORT QAction *save(const QObject *recvr, const char *slot, QObject *parent); /** * Save the current document under a different name. */ KRITAWIDGETUTILS_EXPORT QAction *saveAs(const QObject *recvr, const char *slot, QObject *parent); /** * Revert the current document to the last saved version * (essentially will undo all changes). */ KRITAWIDGETUTILS_EXPORT QAction *revert(const QObject *recvr, const char *slot, QObject *parent); /** * Close the current document. */ KRITAWIDGETUTILS_EXPORT QAction *close(const QObject *recvr, const char *slot, QObject *parent); /** * Print the current document. */ KRITAWIDGETUTILS_EXPORT QAction *print(const QObject *recvr, const char *slot, QObject *parent); /** * Show a print preview of the current document. */ KRITAWIDGETUTILS_EXPORT QAction *printPreview(const QObject *recvr, const char *slot, QObject *parent); /** * Mail this document. */ KRITAWIDGETUTILS_EXPORT QAction *mail(const QObject *recvr, const char *slot, QObject *parent); /** * Quit the program. * * Note that you probably want to connect this action to either QWidget::close() * or QApplication::closeAllWindows(), but not QApplication::quit(), so that * KMainWindow::queryClose() is called on any open window (to warn the user * about unsaved changes for example). */ KRITAWIDGETUTILS_EXPORT QAction *quit(const QObject *recvr, const char *slot, QObject *parent); /** * Undo the last operation. */ KRITAWIDGETUTILS_EXPORT QAction *undo(const QObject *recvr, const char *slot, QObject *parent); /** * Redo the last operation. */ KRITAWIDGETUTILS_EXPORT QAction *redo(const QObject *recvr, const char *slot, QObject *parent); /** * Cut selected area and store it in the clipboard. * Calls cut() on the widget with the current focus. */ KRITAWIDGETUTILS_EXPORT QAction *cut(QObject *parent); /** * Copy selected area and store it in the clipboard. * Calls copy() on the widget with the current focus. */ KRITAWIDGETUTILS_EXPORT QAction *copy(QObject *parent); /** * Paste the contents of clipboard at the current mouse or cursor * Calls paste() on the widget with the current focus. */ KRITAWIDGETUTILS_EXPORT QAction *paste(QObject *parent); /** * Clear selected area. Calls clear() on the widget with the current focus. * Note that for some widgets, this may not provide the intended behavior. For * example if you make use of the code above and a K3ListView has the focus, clear() * will clear all of the items in the list. If this is not the intened behavior * and you want to make use of this slot, you can subclass K3ListView and reimplement * this slot. For example the following code would implement a K3ListView without this * behavior: * * \code * class MyListView : public K3ListView { * Q_OBJECT * public: * MyListView( QWidget * parent = 0, const char * name = 0, WFlags f = 0 ) : K3ListView( parent, name, f ) {} * virtual ~MyListView() {} * public Q_SLOTS: * virtual void clear() {} * }; * \endcode */ KRITAWIDGETUTILS_EXPORT QAction *clear(QObject *parent); /** * Calls selectAll() on the widget with the current focus. */ KRITAWIDGETUTILS_EXPORT QAction *selectAll(QObject *parent); /** * Cut selected area and store it in the clipboard. */ KRITAWIDGETUTILS_EXPORT QAction *cut(const QObject *recvr, const char *slot, QObject *parent); /** * Copy the selected area into the clipboard. */ KRITAWIDGETUTILS_EXPORT QAction *copy(const QObject *recvr, const char *slot, QObject *parent); /** * Paste the contents of clipboard at the current mouse or cursor * position. */ KRITAWIDGETUTILS_EXPORT QAction *paste(const QObject *recvr, const char *slot, QObject *parent); /** * Paste the contents of clipboard at the current mouse or cursor * position. Provide a button on the toolbar with the clipboard history * menu if Klipper is running. */ KRITAWIDGETUTILS_EXPORT QAction *pasteText(const QObject *recvr, const char *slot, QObject *parent); /** * Clear the content of the focus widget */ KRITAWIDGETUTILS_EXPORT QAction *clear(const QObject *recvr, const char *slot, QObject *parent); /** * Select all elements in the current document. */ KRITAWIDGETUTILS_EXPORT QAction *selectAll(const QObject *recvr, const char *slot, QObject *parent); /** * Deselect any selected elements in the current document. */ KRITAWIDGETUTILS_EXPORT QAction *deselect(const QObject *recvr, const char *slot, QObject *parent); /** * Initiate a 'find' request in the current document. */ KRITAWIDGETUTILS_EXPORT QAction *find(const QObject *recvr, const char *slot, QObject *parent); /** * Find the next instance of a stored 'find'. */ KRITAWIDGETUTILS_EXPORT QAction *findNext(const QObject *recvr, const char *slot, QObject *parent); /** * Find a previous instance of a stored 'find'. */ KRITAWIDGETUTILS_EXPORT QAction *findPrev(const QObject *recvr, const char *slot, QObject *parent); /** * Find and replace matches. */ KRITAWIDGETUTILS_EXPORT QAction *replace(const QObject *recvr, const char *slot, QObject *parent); /** * View the document at its actual size. */ KRITAWIDGETUTILS_EXPORT QAction *actualSize(const QObject *recvr, const char *slot, QObject *parent); /** * Fit the document view to the size of the current window. */ KRITAWIDGETUTILS_EXPORT QAction *fitToPage(const QObject *recvr, const char *slot, QObject *parent); /** * Fit the document view to the width of the current window. */ KRITAWIDGETUTILS_EXPORT QAction *fitToWidth(const QObject *recvr, const char *slot, QObject *parent); /** * Fit the document view to the height of the current window. */ KRITAWIDGETUTILS_EXPORT QAction *fitToHeight(const QObject *recvr, const char *slot, QObject *parent); /** * Zoom in. */ KRITAWIDGETUTILS_EXPORT QAction *zoomIn(const QObject *recvr, const char *slot, QObject *parent); /** * Zoom out. */ KRITAWIDGETUTILS_EXPORT QAction *zoomOut(const QObject *recvr, const char *slot, QObject *parent); /** * Popup a zoom dialog. */ KRITAWIDGETUTILS_EXPORT QAction *zoom(const QObject *recvr, const char *slot, QObject *parent); /** * Redisplay or redraw the document. */ KRITAWIDGETUTILS_EXPORT QAction *redisplay(const QObject *recvr, const char *slot, QObject *parent); /** * Move up (web style menu). */ KRITAWIDGETUTILS_EXPORT QAction *up(const QObject *recvr, const char *slot, QObject *parent); /** * Move back (web style menu). */ KRITAWIDGETUTILS_EXPORT QAction *back(const QObject *recvr, const char *slot, QObject *parent); /** * Move forward (web style menu). */ KRITAWIDGETUTILS_EXPORT QAction *forward(const QObject *recvr, const char *slot, QObject *parent); /** * Go to the "Home" position or document. */ KRITAWIDGETUTILS_EXPORT QAction *home(const QObject *recvr, const char *slot, QObject *parent); /** * Scroll up one page. */ KRITAWIDGETUTILS_EXPORT QAction *prior(const QObject *recvr, const char *slot, QObject *parent); /** * Scroll down one page. */ KRITAWIDGETUTILS_EXPORT QAction *next(const QObject *recvr, const char *slot, QObject *parent); /** * Go to somewhere in general. */ KRITAWIDGETUTILS_EXPORT QAction *goTo(const QObject *recvr, const char *slot, QObject *parent); /** * Go to a specific page (dialog). */ KRITAWIDGETUTILS_EXPORT QAction *gotoPage(const QObject *recvr, const char *slot, QObject *parent); /** * Go to a specific line (dialog). */ KRITAWIDGETUTILS_EXPORT QAction *gotoLine(const QObject *recvr, const char *slot, QObject *parent); /** * Jump to the first page. */ KRITAWIDGETUTILS_EXPORT QAction *firstPage(const QObject *recvr, const char *slot, QObject *parent); /** * Jump to the last page. */ KRITAWIDGETUTILS_EXPORT QAction *lastPage(const QObject *recvr, const char *slot, QObject *parent); /** * Move back (document style menu). */ KRITAWIDGETUTILS_EXPORT QAction *documentBack(const QObject *recvr, const char *slot, QObject *parent); /** * Move forward (document style menu). */ KRITAWIDGETUTILS_EXPORT QAction *documentForward(const QObject *recvr, const char *slot, QObject *parent); /** * Add the current page to the bookmarks tree. */ KRITAWIDGETUTILS_EXPORT QAction *addBookmark(const QObject *recvr, const char *slot, QObject *parent); /** * Edit the application bookmarks. */ KRITAWIDGETUTILS_EXPORT QAction *editBookmarks(const QObject *recvr, const char *slot, QObject *parent); /** * Pop up the spell checker. */ KRITAWIDGETUTILS_EXPORT QAction *spelling(const QObject *recvr, const char *slot, QObject *parent); /** * Show/Hide the menubar. */ KRITAWIDGETUTILS_EXPORT KToggleAction *showMenubar(const QObject *recvr, const char *slot, QObject *parent); /** * Show/Hide the statusbar. */ KRITAWIDGETUTILS_EXPORT KToggleAction *showStatusbar(const QObject *recvr, const char *slot, QObject *parent); /** * Switch to/from full screen mode */ KRITAWIDGETUTILS_EXPORT KToggleFullScreenAction *fullScreen(const QObject *recvr, const char *slot, QWidget *window, QObject *parent); /** * Display the save options dialog. */ KRITAWIDGETUTILS_EXPORT QAction *saveOptions(const QObject *recvr, const char *slot, QObject *parent); /** * Display the configure key bindings dialog. * * Note that you might be able to use the pre-built KXMLGUIFactory's function: * KStandardAction::keyBindings(guiFactory(), SLOT(configureShortcuts()), actionCollection()); */ KRITAWIDGETUTILS_EXPORT QAction *keyBindings(const QObject *recvr, const char *slot, QObject *parent); /** * Display the preferences/options dialog. */ KRITAWIDGETUTILS_EXPORT QAction *preferences(const QObject *recvr, const char *slot, QObject *parent); /** * The Customize Toolbar dialog. */ KRITAWIDGETUTILS_EXPORT QAction *configureToolbars(const QObject *recvr, const char *slot, QObject *parent); /** * The Configure Notifications dialog. */ KRITAWIDGETUTILS_EXPORT QAction *configureNotifications(const QObject *recvr, const char *slot, QObject *parent); /** * Display the help. */ KRITAWIDGETUTILS_EXPORT QAction *help(const QObject *recvr, const char *slot, QObject *parent); /** * Display the help contents. */ KRITAWIDGETUTILS_EXPORT QAction *helpContents(const QObject *recvr, const char *slot, QObject *parent); /** * Trigger the What's This cursor. */ KRITAWIDGETUTILS_EXPORT QAction *whatsThis(const QObject *recvr, const char *slot, QObject *parent); /** * Display "Tip of the Day" */ KRITAWIDGETUTILS_EXPORT QAction *tipOfDay(const QObject *recvr, const char *slot, QObject *parent); /** * Open up the Report Bug dialog. */ KRITAWIDGETUTILS_EXPORT QAction *reportBug(const QObject *recvr, const char *slot, QObject *parent); /** * Display the application's About box. */ KRITAWIDGETUTILS_EXPORT QAction *aboutApp(const QObject *recvr, const char *slot, QObject *parent); /** * Display the About KDE dialog. */ KRITAWIDGETUTILS_EXPORT QAction *aboutKDE(const QObject *recvr, const char *slot, QObject *parent); } #endif // KSTDACTION_H diff --git a/libs/widgetutils/xmlgui/KisShortcutsDialog.h b/libs/widgetutils/xmlgui/KisShortcutsDialog.h index 8502616b11..391e0ac78b 100644 --- a/libs/widgetutils/xmlgui/KisShortcutsDialog.h +++ b/libs/widgetutils/xmlgui/KisShortcutsDialog.h @@ -1,178 +1,180 @@ /* This file is part of the KDE libraries Copyright (C) 1997 Nicolas Hadacek Copyright (C) 2001 Ellis Whitehead Copyright (C) 2006 Hamish Rodda Copyright (C) 2007 Roberto Raggi Copyright (C) 2007 Andreas Hartmetz Copyright (C) 2008 Michael Jansen Copyright (C) 2015 Michael Abrahams This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KISSHORTCUTSDIALOG_H #define KISSHORTCUTSDIALOG_H #include #include // Altering this class and some classes it uses was one major impetus behind // forking XmlGui. The first major workaround was to allow // KisPart::configureShortcuts() to pull up the dialog, and to remote the scheme // editor support, since it's incompatible with Krita. // // The files were forked from KF5 XmlGui version 5.12.0 // dialogs/KisShortcutsEditorItem.cpp <- kshortcutseditoritem.cpp // dialogs/KisShortcutEditWidget.cpp <- kshortcuteditwidget.cpp // dialogs/KisShortcutsEditorDelegate.cpp <- kshortcutseditordelegate.cpp // dialogs/KisShortcutsDialog.cpp <- kshortcutsdialog.cpp, , kshortcutsdialog_p.cpp // dialogs/KisShortcutsDialog.h <- kshortcutsdialog.h // dialogs/KisShortcutsDialog_p.h <- kshortcutsdialog_p.h, kshortcutseditor_p.h // forms/KisShortcutsDialog.ui <- kshortcutsdialog.ui // // // Changes that have been done to the files: // * Adapt of includes // * Removing unwanted parts related to schemes // * Renamed KShortcutsDialog/Editor to KisShortcutsDialog/Editor // * Add export macro // * Split apart kshortcutseditor_p // * Copied KShortcutsEditorPrivate::itemFromIndex() implementation from // KF5 XmlGui's kshortcutseditor.cpp to begin of KisShortcutsEditorItem.cpp /** * @short Dialog for configuration of KActionCollection and KGlobalAccel. * * The KisShortcutsDialog class is used for configuring dictionaries of * key/action associations for KActionCollection and KGlobalAccel. It uses the * KShortcutsEditor widget and offers buttons to set all keys to defaults and * invoke on-line help. * * Several static methods are supplied which provide the most convenient * interface to the dialog. The most common and most encouraged use is with * KActionCollection. * * \code * KisShortcutsDialog::configure( actionCollection() ); * \endcode * * @since 4.3 By default this dialog is modal. If you don't want that, * setModal(false) and then the non-static configure() will show the dialog. If * you want to do anything extra when the dialog is done, connect to okClicked() * and/or cancelClicked(). However, if your extra stuff depends on the changed * settings already being saved, connect to saved() instead to be safe; if you * connect to okClicked() your function might be called before the save happens. * * example: * \code * KisShortcutsDialog dlg; * dlg.addCollection(myActions); * dlg.setModal(false); * connect(&dlg, SIGNAL(saved()), this, SLOT(doExtraStuff())); * dlg.configure(); * \endcode * * \image html kshortcutsdialog.png "KDE Shortcuts Dialog" * * @author Nicolas Hadacek * @author Hamish Rodda (KDE 4 porting) * @author Michael Jansen */ const auto defaultActionTypes = KisShortcutsEditor::WidgetAction \ | KisShortcutsEditor::WindowAction \ | KisShortcutsEditor::ApplicationAction; class KRITAWIDGETUTILS_EXPORT KisShortcutsDialog : public QWidget { Q_OBJECT public: /** * Constructs a KisShortcutsDialog. Mostly UI boilerplate. * + * @param types the action types * @param allowLetterShortcuts set to KisShortcutsEditor::LetterShortcutsDisallowed if unmodified alphanumeric * keys ('A', '1', etc.) are not permissible shortcuts. * * @param parent the parent widget to attach to * * There is some legacy support for global (i.e. desktop-wide) shortucts * that should probably be removed. */ explicit KisShortcutsDialog(KisShortcutsEditor::ActionTypes types = defaultActionTypes, KisShortcutsEditor::LetterShortcuts allowLetterShortcuts \ = KisShortcutsEditor::LetterShortcutsAllowed, QWidget *parent = 0); ~KisShortcutsDialog() override; /** * Add all actions of the collection to the ones displayed and configured * by the dialog. This is where the business happens. * + * @param collection the action collection. * @param title the title associated with the collection. */ void addCollection(KActionCollection *, const QString &title = QString()); /** * @return the list of action collections that are available for configuration in the dialog. */ QList actionCollections() const; /** @see QWidget::sizeHint() */ QSize sizeHint() const override; /** * Called when the "OK" button in the main configuration page is pressed. */ void save(); void allDefault(); void undo(); /** * Import shortcut scheme file from @p path */ void importConfiguration(const QString &path); /** * Exports shortcut scheme file to @p path */ void exportConfiguration(const QString &path) const; /** * Import custom shortcuts from @p path */ void loadCustomShortcuts(const QString &path); /** * Exports custom shortcuts to @p path */ void saveCustomShortcuts(const QString &path) const; private: Q_PRIVATE_SLOT(d, void changeShortcutScheme(const QString &)) Q_PRIVATE_SLOT(d, void undo()) class KisShortcutsDialogPrivate; class KisShortcutsDialogPrivate *const d; Q_DISABLE_COPY(KisShortcutsDialog) }; #endif // KISSHORTCUTSDIALOG_H diff --git a/libs/widgetutils/xmlgui/KisShortcutsEditor.h b/libs/widgetutils/xmlgui/KisShortcutsEditor.h index 1d96c0bae8..e7f11aa3c8 100644 --- a/libs/widgetutils/xmlgui/KisShortcutsEditor.h +++ b/libs/widgetutils/xmlgui/KisShortcutsEditor.h @@ -1,256 +1,257 @@ /* This file is part of the KDE libraries Copyright (C) 1997 Nicolas Hadacek Copyright (C) 2001,2001 Ellis Whitehead Copyright (C) 2006 Hamish Rodda Copyright (C) 2007 Roberto Raggi Copyright (C) 2007 Andreas Hartmetz Copyright (C) 2008 Michael Jansen Copyright (c) 2015 Michael Abrahams This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KISSHORTCUTSEDITOR_H #define KISSHORTCUTSEDITOR_H #include #include #include class KActionCollection; class KConfig; class KConfigBase; class KConfigGroup; class KGlobalAccel; class KisShortcutsEditorPrivate; /** * WARNING: KisShortcutsEditor expects that the list of existing shortcuts is * already free of conflicts. If it is not, nothing will crash, but your users * won't like the resulting behavior. * * TODO: Find the right place to check for conflicts. */ /** * @short Widget for configuration of KAccel and KGlobalAccel. * * Configure dictionaries of key/action associations for KActions, * including global shortcuts. * * The class takes care of all aspects of configuration, including * handling key conflicts internally. Connect to the allDefault() * slot if you want to set all configurable shortcuts to their * default values. * * @see KShortcutsDialog * @author Nicolas Hadacek * @author Hamish Rodda (KDE 4 porting) * @author Michael Jansen */ class KRITAWIDGETUTILS_EXPORT KisShortcutsEditor : public QWidget { Q_OBJECT Q_PROPERTY(ActionTypes actionTypes READ actionTypes WRITE setActionTypes) public: /* * These attempt to build some sort of characterization of all actions. The * idea is to determine which sorts of actions will be configured in the * dialog. * * Enumerating all possible actions is a sorrowful, pitiable endeavor, * useless for Krita. We should do something about this. */ enum ActionType { /// Actions which are triggered by any keypress in a widget which has the action added to it WidgetAction = Qt::WidgetShortcut /*0*/, /// Actions which are triggered by any keypress in a window which has the action added to it or its child widget(s) WindowAction = Qt::WindowShortcut /*1*/, /// Actions which are triggered by any keypress in the application ApplicationAction = Qt::ApplicationShortcut /*2*/, /// Actions which are triggered by any keypress in the windowing system GlobalAction = 4, /// All actions AllActions = 0xffffffff }; Q_DECLARE_FLAGS(ActionTypes, ActionType) enum LetterShortcuts { /// Shortcuts without a modifier are not allowed, so 'A' would not be /// valid, whereas 'Ctrl+A' would be. This only applies to printable /// characters, however. 'F1', 'Insert' etc. could still be used. LetterShortcutsDisallowed = 0, /// Letter shortcuts are allowed LetterShortcutsAllowed }; /** * \overload * * Creates a key chooser without a starting action collection. * * @param parent parent widget * @param actionTypes types of actions to display in this widget. * @param allowLetterShortcuts set to LetterShortcutsDisallowed if unmodified alphanumeric * keys ('A', '1', etc.) are not permissible shortcuts. */ explicit KisShortcutsEditor(QWidget *parent, ActionTypes actionTypes = AllActions, LetterShortcuts allowLetterShortcuts = LetterShortcutsAllowed); /// Destructor ~KisShortcutsEditor() override; /** - * @ret true if there are unsaved changes. + * @return @c true if there are unsaved changes. */ bool isModified() const; /** * Removes all action collections from the editor */ void clearCollections(); /** * Clears search area */ void clearSearch(); /** * Note: the reason this is so damn complicated is because it's supposed to * support having multiple applications running inside of each other through * KisParts. That means we have to be able to separate sections within each * configuration file. * * Insert an action collection, i.e. add all its actions to the ones * already associated with the KisShortcutsEditor object. * + * @param collection the action collection. * @param title subtree title of this collection of shortcut. */ void addCollection(KActionCollection *, const QString &title = QString()); /** * Undo all change made since the last commit(). */ void undo(); /** * Save the changes. * * Before saving the changes are committed. This saves the actions to disk. * Any KActionCollection objects with the xmlFile() value set will be * written to an XML file. All other will be written to the application's * rc file. */ void save(); /** * Update the dialog entries without saving. * * @since 4.2 */ void commit(); /** * Removes all configured shortcuts. */ void clearConfiguration(); /** * Write the current custom shortcut settings to the \p config object. * * @param config Config object to save to. Default is kritashortcutsrc. * */ void saveShortcuts(KConfigGroup *config = 0) const; /** * Write the current shortcuts to a new scheme to configuration file * * @param config Config object to save to. */ void exportConfiguration(KConfigBase *config) const; /** * Import a shortcut configuration file. * * @param config Config object to load from. * @param isScheme true for shortcut scheme, false for custom shortcuts */ void importConfiguration(KConfigBase *config, bool isScheme); /** * Sets the types of actions to display in this widget. * * @param actionTypes New types of actions * @since 5.0 */ void setActionTypes(ActionTypes actionTypes); /** * * @return The types of actions currently displayed in this widget. * @since 5.0 */ ActionTypes actionTypes() const; Q_SIGNALS: /** * Emitted when an action's shortcut has been changed. **/ void keyChange(); public Q_SLOTS: /** * Resize columns to width required */ void resizeColumns(); /** * Set all shortcuts to their default values (bindings). **/ void allDefault(); /** * Opens a printing dialog to print all the shortcuts */ void printShortcuts() const; /** * Expand or collapse the tree view when the search text changes */ void searchUpdated(QString s); void slotScrollerStateChanged(QScroller::State state){KisKineticScroller::updateCursor(this, state);} private: Q_PRIVATE_SLOT(d, void capturedShortcut(QVariant, const QModelIndex &)) private: friend class KisShortcutsDialog; friend class KisShortcutsEditorPrivate; KisShortcutsEditorPrivate *const d; Q_DISABLE_COPY(KisShortcutsEditor) }; Q_DECLARE_OPERATORS_FOR_FLAGS(KisShortcutsEditor::ActionTypes) #endif // KISSHORTCUTSEDITOR_H diff --git a/libs/widgetutils/xmlgui/kactioncollection.h b/libs/widgetutils/xmlgui/kactioncollection.h index 8985661090..962aab2531 100644 --- a/libs/widgetutils/xmlgui/kactioncollection.h +++ b/libs/widgetutils/xmlgui/kactioncollection.h @@ -1,514 +1,514 @@ /* This file is part of the KDE libraries Copyright (C) 1999 Reginald Stadlbauer (C) 1999 Simon Hausmann (C) 2000 Nicolas Hadacek (C) 2000 Kurt Granroth (C) 2000 Michael Koch (C) 2001 Holger Freyther (C) 2002 Ellis Whitehead (C) 2005-2006 Hamish Rodda 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 KACTIONCOLLECTION_H #define KACTIONCOLLECTION_H #include "config-xmlgui.h" #include #include #include class QAction; class KXMLGUIClient; class KConfigGroup; class QActionGroup; class QString; class KActionCategory; /** * \short A container for a set of QAction objects. * * KActionCollection manages a set of QAction objects. It * allows them to be grouped for organized presentation of configuration to the user, * saving + loading of configuration, and optionally for automatic plugging into * specified widget(s). * * Additionally, KActionCollection provides several convenience functions for locating * named actions, and actions grouped by QActionGroup. * * \note If you create your own action collection and need to assign shortcuts * to the actions within, you have to call associateWidget() or * addAssociatedWidget() to have them working. */ class KRITAWIDGETUTILS_EXPORT KActionCollection : public QObject { friend class KXMLGUIClient; Q_OBJECT Q_PROPERTY(QString configGroup READ configGroup WRITE setConfigGroup) public: /** * Constructor. Allows specification of a component name other than the default * application name, where needed (remember to call setComponentDisplayName() too). */ explicit KActionCollection(QObject *parent, const QString &cName = QString()); /** * Destructor. */ ~KActionCollection() override; /** * Access the list of all action collections in existence for this app */ static const QList &allCollections(); /** * Clears the entire action collection, deleting all actions. */ void clear(); /** * Associate all actions in this collection to the given \a widget. * Unlike addAssociatedWidget, this method only adds all current actions * in the collection to the given widget. Any action added after this call * will not be added to the given widget automatically. * So this is just a shortcut for a foreach loop and a widget->addAction call. */ void associateWidget(QWidget *widget) const; /** * Associate all actions in this collection to the given \a widget, including any actions * added after this association is made. * * This does not change the action's shortcut context, so if you need to have the actions only * trigger when the widget has focus, you'll need to set the shortcut context on each action * to Qt::WidgetShortcut (or better still, Qt::WidgetWithChildrenShortcut with Qt 4.4+) */ void addAssociatedWidget(QWidget *widget); /** * Remove an association between all actions in this collection and the given \a widget, i.e. * remove those actions from the widget, and stop associating newly added actions as well. */ void removeAssociatedWidget(QWidget *widget); /** * Return a list of all associated widgets. */ QList associatedWidgets() const; /** * Clear all associated widgets and remove the actions from those widgets. */ void clearAssociatedWidgets(); /** * Returns the KConfig group with which settings will be loaded and saved. */ QString configGroup() const; /** * Sets \a group as the KConfig group with which settings will be loaded and saved. */ void setConfigGroup(const QString &group); /** * Read all key associations from @p config. * * If @p config is zero, read all key associations from the * application's configuration file KSharedConfig::openConfig(), * in the group set by setConfigGroup(). */ void readSettings(); /** * Update shortcuts from the KisActionRegistry. */ void updateShortcuts(); /** * Write the current configurable key associations. If @a is nonzero, use * that configuration group. * * Otherwise, the output file is determined as follows. If this action * collection belongs to a KXMLGuiClient the setting are saved to the * kxmlgui definition file. If not the settings are written to the * applications config file. * * \note oneAction() and writeDefaults() have no meaning for the kxmlgui * configuration file. * * \param config Config object to save to, or null (see above) * \param writeScheme set to true if we export all settings as new shortcut scheme * \param oneAction pass an action here if you just want to save the values for one action, eg. * if you know that action is the only one which has changed. */ void writeSettings(KConfigGroup *config = 0, bool writeScheme = false, QAction *oneAction = 0) const; /** * Returns the number of actions in the collection. * * This is equivalent to actions().count(). */ int count() const; /** * Returns whether the action collection is empty or not. */ bool isEmpty() const; /** * Return the QAction* at position "index" in the action collection. * * This is equivalent to actions().value(index); */ QAction *action(int index) const; /** * Get the action with the given \a name from the action collection. * * @param name Name of the QAction * @return A pointer to the QAction in the collection which matches the parameters or * null if nothing matches. */ QAction *action(const QString &name) const; /** * Returns the list of QActions which belong to this action collection. * * The list is guaranteed to be in the same order the action were put into * the collection. */ QList actions() const; /** * Returns the list of QActions without an QAction::actionGroup() which belong to this action collection. */ const QList actionsWithoutGroup() const; /** * Returns the list of all QActionGroups associated with actions in this action collection. */ const QList actionGroups() const; /** * Set the \a componentName associated with this action collection. * * \warning Don't call this method on a KActionCollection that contains * actions. This is not supported. * - * \param componentData the name which is to be associated with this action collection, + * \param componentName the name which is to be associated with this action collection, * or QString() to indicate the app name. This is used to load/save settings into XML files. * KXmlGuiClient::setComponentName takes care of calling this. */ void setComponentName(const QString &componentName); /** The component name with which this class is associated. */ QString componentName() const; /** * Set the component display name associated with this action collection. * (e.g. for the toolbar editor) * KXmlGuiClient::setComponentName takes care of calling this. */ void setComponentDisplayName(const QString &displayName); /** The display name for the associated component. */ QString componentDisplayName() const; /** * The parent KXMLGUIClient, or null if not available. */ const KXMLGUIClient *parentGUIClient() const; /** * Returns the KActionCategories inside this collection */ QList categories() const; /** * Gets a category with name @p name inside this collection. * * Creates a new category if one does not exist. */ KActionCategory *getCategory(const QString &categoryName); Q_SIGNALS: /** * Indicates that \a action was inserted into this action collection. */ void inserted(QAction *action); /** * Indicates that \a action was removed from this action collection. * @deprecated */ QT_MOC_COMPAT void removed(QAction *action); /** * Indicates that \a action was highlighted (hovered over). * @deprecated Replaced by actionHovered(QAction* action); */ QT_MOC_COMPAT void actionHighlighted(QAction *action); /** * Indicates that \a action was hovered. */ void actionHovered(QAction *action); /** * Indicates that \a action was triggered */ void actionTriggered(QAction *action); protected: /// Overridden to perform connections when someone wants to know whether an action was highlighted or triggered void connectNotify(const QMetaMethod &signal) override; protected Q_SLOTS: virtual void slotActionTriggered(); /** * @internal * @deprecated Replaced by slotActionHovered(); */ QT_MOC_COMPAT virtual void slotActionHighlighted(); private Q_SLOTS: void slotActionHovered(); public: /** * Add an action under the given name to the collection. * * Inserting an action that was previously inserted under a different name will replace the * old entry, i.e. the action will not be available under the old name anymore but only under * the new one. * * Inserting an action under a name that is already used for another action will replace * the other action in the collection (but will not delete it). * * If KAuthorized::authorizeKAction() reports that the action is not * authorized, it will be disabled and hidden. * * @param name The name by which the action be retrieved again from the collection. * @param action The action to add. * @return the same as the action given as parameter. This is just for convenience * (chaining calls) and consistency with the other addAction methods, you can also * simply ignore the return value. */ Q_INVOKABLE QAction *addAction(const QString &name, QAction *action); /** * Adds a new action to the collection in category @p category. * * The category will be created if it does not already exist. */ Q_INVOKABLE QAction *addCategorizedAction(const QString &name, QAction *action, const QString &categoryName); /** * Adds a list of actions to the collection. * * The objectName of the actions is used as their internal name in the collection. * * Uses addAction(QString, QAction*). * * @param actions the list of the actions to add. * * @see addAction() * @since 5.0 */ void addActions(const QList &actions); /** * Removes an action from the collection and deletes it. * @param action The action to remove. */ void removeAction(QAction *action); /** * Removes an action from the collection. * @param action the action to remove. */ QAction *takeAction(QAction *action); /** * Creates a new standard action, adds it to the collection and connects the * action's triggered(bool) signal to the specified receiver/member. The * newly created action is also returned. * * Note: Using KStandardAction::OpenRecent will cause a different signal than * triggered(bool) to be used, see KStandardAction for more information. * * The action can be retrieved later from the collection by its standard name as per * KStandardAction::stdName. * * @param actionType The standard action type of the action to create. * @param receiver The QObject to connect the triggered(bool) signal to. Leave 0 if no * connection is desired. * @param member The SLOT to connect the triggered(bool) signal to. Leave 0 if no * connection is desired. * @return new action of the given type ActionType. */ QAction *addAction(KStandardAction::StandardAction actionType, const QObject *receiver = 0, const char *member = 0); /** * Creates a new standard action, adds to the collection under the given name * and connects the action's triggered(bool) signal to the specified * receiver/member. The newly created action is also returned. * * Note: Using KStandardAction::OpenRecent will cause a different signal than * triggered(bool) to be used, see KStandardAction for more information. * * The action can be retrieved later from the collection by the specified name. * * @param actionType The standard action type of the action to create. * @param name The name by which the action be retrieved again from the collection. * @param receiver The QObject to connect the triggered(bool) signal to. Leave 0 if no * connection is desired. * @param member The SLOT to connect the triggered(bool) signal to. Leave 0 if no * connection is desired. * @return new action of the given type ActionType. */ QAction *addAction(KStandardAction::StandardAction actionType, const QString &name, const QObject *receiver = 0, const char *member = 0); /** * Creates a new action under the given name to the collection and connects * the action's triggered(bool) signal to the specified receiver/member. The * newly created action is returned. * * NOTE: KDE prior to 4.2 used the triggered() signal instead of the triggered(bool) * signal. * * Inserting an action that was previously inserted under a different name will replace the * old entry, i.e. the action will not be available under the old name anymore but only under * the new one. * * Inserting an action under a name that is already used for another action will replace * the other action in the collection. * * @param name The name by which the action be retrieved again from the collection. * @param receiver The QObject to connect the triggered(bool) signal to. Leave 0 if no * connection is desired. * @param member The SLOT to connect the triggered(bool) signal to. Leave 0 if no * connection is desired. * @return new action of the given type ActionType. */ QAction *addAction(const QString &name, const QObject *receiver = 0, const char *member = 0); /** * Creates a new action under the given name, adds it to the collection and connects the action's triggered(bool) * signal to the specified receiver/member. The receiver slot may accept either a bool or no * parameters at all (i.e. slotTriggered(bool) or slotTriggered() ). * The type of the action is specified by the template parameter ActionType. * * NOTE: KDE prior to 4.2 connected the triggered() signal instead of the triggered(bool) * signal. * * @param name The internal name of the action (e.g. "file-open"). * @param receiver The QObject to connect the triggered(bool) signal to. Leave 0 if no * connection is desired. * @param member The SLOT to connect the triggered(bool) signal to. Leave 0 if no * connection is desired. * @return new action of the given type ActionType. * * @see addAction() */ template ActionType *add(const QString &name, const QObject *receiver = 0, const char *member = 0) { ActionType *a = new ActionType(this); if (receiver && member) { connect(a, SIGNAL(triggered(bool)), receiver, member); } addAction(name, a); return a; } /** * Get the default primary shortcut for the given action. * * @param action the action for which the default primary shortcut should be returned. * @return the default primary shortcut of the given action * @since 5.0 */ QKeySequence defaultShortcut(QAction *action) const; /** * Get the default shortcuts for the given action. * * @param action the action for which the default shortcuts should be returned. * @return the default shortcuts of the given action * @since 5.0 */ QList defaultShortcuts(QAction *action) const; //TODO KF6: Make setDefaultShortcut static /** * Set the default shortcut for the given action. * Since 5.2, this also calls action->setShortcut(shortcut), i.e. the default shortcut is * made active initially. * * @param action the action for which the default shortcut should be set. * @param shortcut the shortcut to use for the given action in its specified shortcutContext() * @since 5.0 */ void setDefaultShortcut(QAction *action, const QKeySequence &shortcut); /** * Set the default shortcuts for the given action. * Since 5.2, this also calls action->setShortcuts(shortcuts), i.e. the default shortcut is * made active initially. * * @param action the action for which the default shortcut should be set. * @param shortcuts the shortcuts to use for the given action in its specified shortcutContext() * @since 5.0 */ Q_INVOKABLE void setDefaultShortcuts(QAction *action, const QList &shortcuts); /** * Returns true if the given action's shortcuts may be configured by the user. * * @param action the action for the hint should be verified. * @since 5.0 */ bool isShortcutsConfigurable(QAction *action) const; /** * Indicate whether the user may configure the action's shortcuts. * * @param action the action for the hint should be verified. * @param configurable set to true if the shortcuts of the given action may be configured by the user, otherwise false. * @since 5.0 */ void setShortcutsConfigurable(QAction *action, bool configurable); private: Q_PRIVATE_SLOT(d, void _k_actionDestroyed(QObject *)) Q_PRIVATE_SLOT(d, void _k_associatedWidgetDestroyed(QObject *)) KActionCollection(const KXMLGUIClient *parent); // used by KXMLGUIClient friend class KActionCollectionPrivate; class KActionCollectionPrivate *const d; }; #endif diff --git a/libs/widgetutils/xmlgui/kedittoolbar.h b/libs/widgetutils/xmlgui/kedittoolbar.h index 6ab950ed07..af06e473ae 100644 --- a/libs/widgetutils/xmlgui/kedittoolbar.h +++ b/libs/widgetutils/xmlgui/kedittoolbar.h @@ -1,158 +1,158 @@ /* This file is part of the KDE libraries Copyright (C) 2000 Kurt Granroth Copyright (C) 2006 Hamish Rodda 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 KEDITTOOLBAR_H #define KEDITTOOLBAR_H #include #include class KActionCollection; class KEditToolBarPrivate; class KXMLGUIFactory; /** * @short A dialog used to customize or configure toolbars. * * This dialog only works if your application uses the XML UI * framework for creating menus and toolbars. It depends on the XML * files to describe the toolbar layouts and it requires the actions * to determine which buttons are active. * * Typically you do not need to use it directly as KXmlGuiWindow::setupGUI * takes care of it. * * If you use plugListAction you need to overload saveNewToolbarConfig() * to plug actions again: * * \code * void MyClass::saveNewToolbarConfig() * { * KXmlGuiWindow::saveNewToolbarConfig(); * plugActionList( "list1", list1Actions ); * plugActionList( "list2", list2Actions ); * } * \endcode * * When created, KEditToolBar takes a KXMLGUIFactory object, and uses it to * find all of the action collections and XML files (there is one of each for the * mainwindow, but there could be more, when adding other XMLGUI clients like * KParts or plugins). The editor aims to be semi-intelligent about where it * assigns any modifications. In other words, it will not write out part specific * changes to your application's main XML file. * * KXmlGuiWindow and KParts::MainWindow take care of creating KEditToolBar correctly * and connecting to its newToolBarConfig slot, but if you really really want to do it * yourself, see the KXmlGuiWindow::configureToolbars() and KXmlGuiWindow::saveNewToolbarConfig() code. * * \image html kedittoolbar.png "KDE Toolbar Editor (KWrite)" * * @author Kurt Granroth * @maintainer David Faure */ class KRITAWIDGETUTILS_EXPORT KEditToolBar : public QDialog { Q_OBJECT public: /** * Main constructor. * * The main parameter, @p factory, is a pointer to the * XML GUI factory object for your application. It contains a list * of all of the GUI clients (along with the action collections and * xml files) and the toolbar editor uses that. * * Use this like so: * \code * KEditToolBar edit(factory()); * if (edit.exec()) * ... * \endcode * * @param factory Your application's factory object * @param parent The usual parent for the dialog. */ explicit KEditToolBar(KXMLGUIFactory *factory, QWidget *parent = 0); /// destructor ~KEditToolBar() override; /** * Sets the default toolbar that will be selected when the dialog is shown. * If not set, or QString() is passed in, the global default tool bar name * will be used. * @param toolBarName the name of the tool bar * @see setGlobalDefaultToolBar */ void setDefaultToolBar(const QString &toolBarName); /** * The name (absolute or relative) of your application's UI resource file * is assumed to be share/apps/appname/appnameui.xmlgui though this can be * overridden by calling this method. * * The global parameter controls whether or not the * global resource file is used. If this is @p true, then you may * edit all of the actions in your toolbars -- global ones and * local one. If it is @p false, then you may edit only your * application's entries. The only time you should set this to * false is if your application does not use the global resource * file at all (very rare). * - * @param xmlfile The application's local resource file. + * @param file The application's local resource file. * @param global If @p true, then the global resource file will also * be parsed. */ void setResourceFile(const QString &file, bool global = true); /** * Sets the default toolbar which will be auto-selected for all * KEditToolBar instances. Can be overridden on a per-dialog basis * by calling setDefaultToolBar( const QString& ) on the dialog. - * @param toolbarName the name of the tool bar + * @param toolBarName the name of the tool bar */ static void setGlobalDefaultToolBar(const char *toolBarName); // TODO should be const QString& Q_SIGNALS: /** * Signal emitted when 'apply' or 'ok' is clicked or toolbars were reset. * Connect to it, to plug action lists and to call applyMainWindowSettings * (see sample code in this class's documentation) */ void newToolBarConfig(); QT_MOC_COMPAT void newToolbarConfig(); protected: void showEvent(QShowEvent *event) override; void hideEvent(QHideEvent *event) override; private: friend class KEditToolBarPrivate; KEditToolBarPrivate *const d; Q_PRIVATE_SLOT(d, void _k_slotButtonClicked(QAbstractButton *)) Q_PRIVATE_SLOT(d, void _k_acceptOK(bool)) Q_PRIVATE_SLOT(d, void _k_enableApply(bool)) Q_DISABLE_COPY(KEditToolBar) }; #endif // _KEDITTOOLBAR_H diff --git a/libs/widgetutils/xmlgui/kedittoolbar_p.h b/libs/widgetutils/xmlgui/kedittoolbar_p.h index 52f31c2a5e..56f9df7233 100644 --- a/libs/widgetutils/xmlgui/kedittoolbar_p.h +++ b/libs/widgetutils/xmlgui/kedittoolbar_p.h @@ -1,256 +1,255 @@ /* This file is part of the KDE libraries Copyright (C) 2000 Kurt Granroth Copyright (C) 2006 Hamish Rodda 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 KEDITTOOLBARP_H #define KEDITTOOLBARP_H #include "kxmlguiclient.h" #include #include class QDialogButtonBox; class QLineEdit; class QCheckBox; namespace KDEPrivate { class ToolBarItem; class KEditToolBarWidgetPrivate; class ToolBarListWidget : public QListWidget { Q_OBJECT public: ToolBarListWidget(QWidget *parent = 0); void makeVisible(QListWidgetItem *item) { scrollTo(indexFromItem(item)); } ToolBarItem *currentItem() const; void setActiveList(bool isActiveList) { m_activeList = isActiveList; } Q_SIGNALS: void dropped(ToolBarListWidget *list, int index, ToolBarItem *item, bool sourceIsActiveList); protected: Qt::DropActions supportedDropActions() const override { return Qt::MoveAction; } QStringList mimeTypes() const override { return QStringList() << QStringLiteral("application/x-kde-action-list"); } QMimeData *mimeData(const QList items) const override; bool dropMimeData(int index, const QMimeData *data, Qt::DropAction action) override; // Skip internal dnd handling in QListWidget ---- how is one supposed to figure this out // without reading the QListWidget code !? void dropEvent(QDropEvent *ev) override { QAbstractItemView::dropEvent(ev); } private: bool m_activeList; }; class IconTextEditDialog : public QDialog { Q_OBJECT public: explicit IconTextEditDialog(QWidget *parent = 0); public: void setIconText(const QString &text); QString iconText() const; void setTextAlongsideIconHidden(bool hidden); bool textAlongsideIconHidden() const; private Q_SLOTS: void slotTextChanged(const QString &text); private: QLineEdit *m_lineEdit; QCheckBox *m_cbHidden; QDialogButtonBox *m_buttonBox; }; /** * @short A widget used to customize or configure toolbars * * This is the widget that does all of the work for the * KEditToolBar dialog. In most cases, you will want to use the * dialog instead of this widget directly. * * Typically, you would use this widget only if you wanted to embed * the toolbar editing directly into your existing configure or * preferences dialog. * * This widget only works if your application uses the XML UI * framework for creating menus and toolbars. It depends on the XML * files to describe the toolbar layouts and it requires the actions * to determine which buttons are active. * * @author Kurt Granroth * @internal */ class KEditToolBarWidget : public QWidget, virtual public KXMLGUIClient { Q_OBJECT public: /** * Old constructor for apps that do not use components. * This constructor is somewhat deprecated, since it doesn't work * with any KXMLGuiClient being added to the mainwindow. * You really want to use the other constructor. * * You @em must pass along your collection of actions (some of which appear in your toolbars). * Then call old-style load. * * @param collection The collection of actions to work on * @param parent This widget's parent */ explicit KEditToolBarWidget(KActionCollection *collection, QWidget *parent = 0L); /** * Main constructor. * * Use this like so: * \code * KEditToolBarWidget widget(this); * widget.load(factory()); * ... * \endcode * - * @param factory Your application's factory object * @param parent This widget's parent */ explicit KEditToolBarWidget(QWidget *parent = 0L); /** * Destructor. Note that any changes done in this widget will * @p NOT be saved in the destructor. You @p must call save() * to do that. */ ~KEditToolBarWidget() override; /** * Old-style load. * * Loads the toolbar configuration into the widget. Should be called before being shown. * * @param resourceFile the name (absolute or relative) of your application's UI * resource file. If it is left blank, then the resource file: share/apps/appname/appnameui.xmlgui * is used. This is the same resource file that is used by the * default createGUI function in KMainWindow so you're usually * pretty safe in leaving it blank. * * @param global controls whether or not the * global resource file is used. If this is true, then you may * edit all of the actions in your toolbars -- global ones and * local one. If it is false, then you may edit only your * application's entries. The only time you should set this to * false is if your application does not use the global resource * file at all (very rare) * * @param defaultToolBar the default toolbar that will be selected when the dialog is shown. * If not set, or QString() is passed in, the global default tool bar name * will be used. * * @see KEditToolBar */ void load(const QString &resourceFile, bool global = true, const QString &defaultToolBar = QString()); /** * Loads the toolbar configuration into the widget. Should be called before being shown. * * @param factory pointer to the XML GUI factory object for your application. * It contains a list of all of the GUI clients (along with the action * collections and xml files) and the toolbar editor uses that. * * @param defaultToolBar the default toolbar that will be selected when the dialog is shown. * If not set, or QString() is passed in, the global default tool bar name * will be used. * * @see KEditToolBar */ void load(KXMLGUIFactory *factory, const QString &defaultToolBar = QString()); /** * @internal Reimplemented for internal purposes. */ KActionCollection *actionCollection() const override; /** * Save any changes the user made. The file will be in the user's * local directory (usually $HOME/.kde/share/apps/\). The * filename will be the one specified in the constructor.. or the * made up one if the filename was NULL. * */ void save(); /** * Remove and readd all KMXLGUIClients to update the GUI */ void rebuildKXMLGUIClients(); Q_SIGNALS: /** * Emitted whenever any modifications are made by the user. */ void enableOk(bool); private: Q_PRIVATE_SLOT(d, void slotToolBarSelected(int index)) Q_PRIVATE_SLOT(d, void slotInactiveSelectionChanged()) Q_PRIVATE_SLOT(d, void slotActiveSelectionChanged()) Q_PRIVATE_SLOT(d, void slotInsertButton()) Q_PRIVATE_SLOT(d, void slotRemoveButton()) Q_PRIVATE_SLOT(d, void slotUpButton()) Q_PRIVATE_SLOT(d, void slotDownButton()) Q_PRIVATE_SLOT(d, void slotDropped(ToolBarListWidget *, int, ToolBarItem *, bool)) private: friend class KEditToolBarWidgetPrivate; KEditToolBarWidgetPrivate *const d; Q_DISABLE_COPY(KEditToolBarWidget) }; } #endif diff --git a/libs/widgetutils/xmlgui/kgesture_p.h b/libs/widgetutils/xmlgui/kgesture_p.h index 4f50c9e107..2889529315 100644 --- a/libs/widgetutils/xmlgui/kgesture_p.h +++ b/libs/widgetutils/xmlgui/kgesture_p.h @@ -1,246 +1,247 @@ /* This file is part of the KDE libraries Copyright (C) 2006,2007 Andreas Hartmetz (ahartmetz@gmail.com) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KGESTURE_H #define KGESTURE_H #include #include #include #include /* kinds of gestures: -shapes like triangle, right angle, line -"rocker" (i.e. two mouse button) gestures */ class KShapeGesturePrivate; //TODO: implement operator== for special situations like in KKeyChooser. class KRITAWIDGETUTILS_EXPORT KShapeGesture { public: /** * Create a new invalid shape gesture. */ KShapeGesture(); /** * Creates a new gesture consisting of given shape. * If the gesture belongs to a KAction, and the user draws approximately the same shape * on the screen while holding down the right mouse button, the action will trigger. * @p shape must be a "reasonable" polygon. It must contain at least two points * and it should contain at most 50 for performance reasons. No two consecutive points * are allowed to be at the same position. * @param shape shape to draw to trigger this gesture */ KShapeGesture(const QPolygon &shape); /** * Creates a new gesture from a string description. * @param description create gesture according to this */ KShapeGesture(const QString &description); /** * Copies the given gesture. * @param other gesture to copy */ KShapeGesture(const KShapeGesture &other); /** * Destructor. */ ~KShapeGesture(); /** * Set the shape to draw to trigger this gesture. */ void setShape(const QPolygon &shape); /** * set a user-visible name for this gesture's shape, like "triangle" or "line". */ void setShapeName(const QString &friendlyName); /** * Return the user-visible name for this gesture's shape, like "triangle" or "line". */ QString shapeName() const; /** * Return true if this gesture is valid. * */ bool isValid() const; /** * Return a string representation of this gesture. * Return empty string if invalid. * This function is mainly for use with config files. * * @see shapeName() */ QString toString() const; /** * Return an idealized SVG image of this gesture. * Return an empty image if invalid. * @param attributes SVG attributes to apply to the SVG "path" element that * makes up the drawing of the gesture. By default, only a 'fill="none"' * attribute will be set. */ QByteArray toSvg(const QString &attributes = QString()) const; /** * Return a difference measurement betwenn this gesture and the @p other * gesture. Abort comparison if difference is larger than @p abortThreshold * and return a very large difference in that case. * Usual return values range from x to y //TODO: fill in x and y */ float distance(const KShapeGesture &other, float abortThreshold) const; /** * Set this gesture to the other gesture. */ KShapeGesture &operator=(const KShapeGesture &other); /** * Return whether this gesture is equal to the other gesture. */ bool operator==(const KShapeGesture &other) const; /** * Return the opposite of operator==() */ bool operator!=(const KShapeGesture &other) const; /** * Return an opaque value for use in hash tables */ uint hashable() const; private: KShapeGesturePrivate *const d; }; inline uint qHash(const KShapeGesture &key) { return qHash(key.hashable()); } class KRockerGesturePrivate; class KRITAWIDGETUTILS_EXPORT KRockerGesture { public: /** * Create a new invalid rocker gesture. */ KRockerGesture(); /** * Creates a new gesture consisting of given buttons. - * @param description create gesture according to this + * @param hold create gesture according to this hold + * @param thenPush create gesture according to this push */ KRockerGesture(enum Qt::MouseButton hold, enum Qt::MouseButton thenPush); /** * Creates a new gesture from a string description. * @param description create gesture according to this */ KRockerGesture(const QString &description); /** * Copies the given gesture. * @param other gesture to copy */ KRockerGesture(const KRockerGesture &other); /** * Destructor. */ ~KRockerGesture(); /** * set button combination to trigger */ void setButtons(Qt::MouseButton hold, Qt::MouseButton thenPush); /** * Write the button combination to hold and thenPush */ void getButtons(Qt::MouseButton *hold, Qt::MouseButton *thenPush) const; /** * Return a user-friendly name of the button combination. */ QString rockerName() const; /** * Return a user-friendly name for the mouse button button */ static QString mouseButtonName(Qt::MouseButton button); /** * Return true if this gesture is valid. */ bool isValid() const; /** * Return a string representation of this gesture. * Return an empty string if invalid. * This function is mainly for use with config files. * * @see rockerName() */ QString toString() const; /** * Set this gesture to the other gesture. */ KRockerGesture &operator=(const KRockerGesture &other); /** * Return whether this gesture is equal to the other gesture. */ bool operator==(const KRockerGesture &other) const; /** * Return the opposite of operator==() */ bool operator!=(const KRockerGesture &other) const; /** * Return an opaque value for use in hash tables */ uint hashable() const; private: KRockerGesturePrivate *const d; }; inline uint qHash(const KRockerGesture &key) { return qHash(key.hashable()); } //KGESTURE_H #endif diff --git a/libs/widgetutils/xmlgui/kswitchlanguagedialog_p.h b/libs/widgetutils/xmlgui/kswitchlanguagedialog_p.h index 573198b5e1..92880eeeca 100644 --- a/libs/widgetutils/xmlgui/kswitchlanguagedialog_p.h +++ b/libs/widgetutils/xmlgui/kswitchlanguagedialog_p.h @@ -1,94 +1,89 @@ /* * This file is part of the KDE Libraries * Copyright (C) 2007 Krzysztof Lichota (lichota@mimuw.edu.pl) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #ifndef _KSWITCHLANGUAGEDIALOG_H_ #define _KSWITCHLANGUAGEDIALOG_H_ #include namespace KDEPrivate { class KSwitchLanguageDialogPrivate; /** * @short Standard "switch application language" dialog box. * * This class provides "switch application language" dialog box that is used * in KHelpMenu * * @author Krzysztof Lichota (lichota@mimuw.edu.pl) * @internal */ class KSwitchLanguageDialog : public QDialog { Q_OBJECT public: /** * Constructor. Creates a fully featured "Switch application language" dialog box. * Note that this dialog is made modeless in the KHelpMenu class so * the users may expect a modeless dialog. * * @param parent The parent of the dialog box. You should use the * toplevel window so that the dialog becomes centered. - * @param name Internal name of the widget. This name in not used in the - * caption. - * @param modal If false, this widget will be modeless and must be - * made visible using QWidget::show(). Otherwise it will be - * modal and must be made visible using QWidget::exec() */ KSwitchLanguageDialog(QWidget *parent = 0); ~KSwitchLanguageDialog() override; protected Q_SLOTS: /** * Activated when the Ok button has been clicked. */ virtual void slotOk(); void slotDefault(); /** Called when one of language buttons changes state. */ virtual void languageOnButtonChanged(const QString &); /** Called to add one language button to dialog. */ virtual void slotAddLanguageButton(); /** Called when "Remove" language button is clicked. */ virtual void removeButtonClicked(); private: KSwitchLanguageDialogPrivate *const d; friend class KSwitchLanguageDialogPrivate; }; } #endif diff --git a/libs/widgetutils/xmlgui/ktoggletoolbaraction.h b/libs/widgetutils/xmlgui/ktoggletoolbaraction.h index 63653ef29f..2110b6daf6 100644 --- a/libs/widgetutils/xmlgui/ktoggletoolbaraction.h +++ b/libs/widgetutils/xmlgui/ktoggletoolbaraction.h @@ -1,95 +1,98 @@ /* This file is part of the KDE libraries Copyright (C) 1999 Reginald Stadlbauer (C) 1999 Simon Hausmann (C) 2000 Nicolas Hadacek (C) 2000 Kurt Granroth (C) 2000 Michael Koch (C) 2001 Holger Freyther (C) 2002 Ellis Whitehead (C) 2003 Andras Mantia (C) 2005-2006 Hamish Rodda 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 KTOGGLETOOLBARACTION_H #define KTOGGLETOOLBARACTION_H #include #include class KToolBar; /** * An action that takes care of everything associated with * showing or hiding a toolbar by a menu action. It will * show or hide the toolbar with the given name when * activated, and check or uncheck itself if the toolbar * is manually shown or hidden. * * If you need to perform some additional action when the * toolbar is shown or hidden, connect to the toggled(bool) * signal. It will be emitted after the toolbar's * visibility has changed, whenever it changes. */ class KRITAWIDGETUTILS_EXPORT KToggleToolBarAction : public KToggleAction { Q_OBJECT public: /** * Create a KToggleToolbarAction that manages the toolbar - * named toolBarName. This can be either the name of a + * named @p toolBarName. This can be either the name of a * toolbar in an xml ui file, or a toolbar programmatically * created with that name. * - * @param The action's parent object. + * @param toolBarName The toolbar name. + * @param text The toolbar hint text. + * @param parent The action's parent object. */ KToggleToolBarAction(const char *toolBarName, const QString &text, QObject *parent); /** - * Create a KToggleToolbarAction that manages the @param toolBar. + * Create a KToggleToolbarAction that manages the @p toolBar. * This can be either the name of a toolbar in an xml ui file, * or a toolbar programmatically created with that name. * * @param toolBar the toolbar to be managed + * @param text The action's text * @param parent The action's parent object. */ KToggleToolBarAction(KToolBar *toolBar, const QString &text, QObject *parent); /** * Destroys toggle toolbar action. */ ~KToggleToolBarAction() override; /** * Returns a pointer to the tool bar it manages. */ KToolBar *toolBar(); /** * Reimplemented from @see QObject. */ bool eventFilter(QObject *watched, QEvent *event) override; private Q_SLOTS: void slotToggled(bool checked) override; private: class Private; Private *const d; }; #endif diff --git a/libs/widgetutils/xmlgui/ktoolbar.h b/libs/widgetutils/xmlgui/ktoolbar.h index 447a03f7cf..6931e61243 100644 --- a/libs/widgetutils/xmlgui/ktoolbar.h +++ b/libs/widgetutils/xmlgui/ktoolbar.h @@ -1,215 +1,215 @@ /* This file is part of the KDE libraries Copyright (C) 2000 Reginald Stadlbauer (reggie@kde.org) (C) 1997, 1998 Stephan Kulow (coolo@kde.org) (C) 1997, 1998 Sven Radej (radej@kde.org) (C) 1997, 1998 Mark Donohoe (donohoe@kde.org) (C) 1997, 1998 Matthias Ettrich (ettrich@kde.org) (C) 1999, 2000 Kurt Granroth (granroth@kde.org) (C) 2005-2006 Hamish Rodda (rodda@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 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 KTOOLBAR_H #define KTOOLBAR_H #include #include class QDomElement; class KConfigGroup; class KConfig; class KMainWindow; class KXMLGUIClient; /** * @short Floatable toolbar with auto resize. * * A KDE-style toolbar. * * KToolBar can be used as a standalone widget, but KMainWindow * provides easy factories and management of one or more toolbars. * * KToolBar uses a global config group to load toolbar settings on * construction. It will reread this config group on a * KApplication::appearanceChanged() signal. * * KToolBar respects Kiosk settings (see the KAuthorized namespace in the * KConfig framework). In particular, system administrators can prevent users * from moving toolbars with the "movable_toolbars" action, and from showing or * hiding toolbars with the "options_show_toolbar" action. For example, to * disable both, add the following the application or global configuration: * @verbatim [KDE Action Restrictions][$i] movable_toolbars=false options_show_toolbar=false @endverbatim * * @note If you can't depend on KXmlGui but you want to integrate with KDE, you can use QToolBar with: * Set ToolButtonStyle to Qt::ToolButtonFollowStyle, this will make QToolBar use the settings for "Main Toolbar" * Additionally set QToolBar::setProperty("otherToolbar", true) to use settings for "Other toolbars" * Settings from "Other toolbars" will only work on widget styles derived from KStyle * @author Reginald Stadlbauer , Stephan Kulow , Sven Radej , Hamish Rodda . */ class KRITAWIDGETUTILS_EXPORT KToolBar : public QToolBar { Q_OBJECT public: /** * Constructor. * * This constructor takes care of adding the toolbar to the mainwindow, * if @p parent is a QMainWindow. * * Normally KDE applications do not call this directly, they either * call KMainWindow::toolBar(name), or they use XML-GUI and specify * toolbars using XML. * * @param objectName The QObject name of this toolbar, required so that QMainWindow can save and load the toolbar position, * and so that KToolBar can find out if it's the main toolbar. * @param parent The standard toolbar parent (usually a KMainWindow) * @param readConfig whether to apply the configuration (global and application-specific) */ explicit KToolBar(const QString &objectName, QWidget *parent, bool readConfig = true); /** * Destroys the toolbar. */ ~KToolBar() override; /** * Returns the main window that this toolbar is docked with. */ KMainWindow *mainWindow() const; /** * Convenience function to set icon size */ void setIconDimensions(int size); /** * Returns the default size for this type of toolbar. * * @return the default size for this type of toolbar. */ int iconSizeDefault() const; // KDE5: hide from public API. Doesn't make sense to export this, and it isn't used. /** * Save the toolbar settings to group @p configGroup in @p config. */ void saveSettings(KConfigGroup &cg); /** * Read the toolbar settings from group @p configGroup in @p config * and apply them. */ void applySettings(const KConfigGroup &cg); /** * Adds an XML gui client that uses this toolbar * @since 4.8.1 */ void addXMLGUIClient(KXMLGUIClient *client); /** * Removes an XML gui client that uses this toolbar * @since 4.8.5 */ void removeXMLGUIClient(KXMLGUIClient *client); /** - * Load state from an XML @param element, called by KXMLGUIBuilder. + * Load state from an XML @p element, called by KXMLGUIBuilder. */ void loadState(const QDomElement &element); /** - * Save state into an XML @param element, called by KXMLGUIBuilder. + * Save state into an XML @p element, called by KXMLGUIBuilder. */ void saveState(QDomElement &element) const; /** * Reimplemented to support context menu activation on disabled tool buttons. */ bool eventFilter(QObject *watched, QEvent *event) override; /** * Returns whether the toolbars are currently editable (drag & drop of actions). */ static bool toolBarsEditable(); /** * Enable or disable toolbar editing via drag & drop of actions. This is * called by KEditToolbar and should generally be set to disabled whenever * KEditToolbar is not active. */ static void setToolBarsEditable(bool editable); /** * Returns whether the toolbars are locked (i.e., moving of the toobars disallowed). */ static bool toolBarsLocked(); /** * Allows you to lock and unlock all toolbars (i.e., disallow/allow moving of the toobars). */ static void setToolBarsLocked(bool locked); /** * Emits a dbus signal to tell all toolbars in all applications, that the user settings have * changed. * @since 5.0 */ static void emitToolbarStyleChanged(); protected Q_SLOTS: virtual void slotMovableChanged(bool movable); protected: void contextMenuEvent(QContextMenuEvent *) override; void actionEvent(QActionEvent *) override; // Draggable toolbar configuration void dragEnterEvent(QDragEnterEvent *) override; void dragMoveEvent(QDragMoveEvent *) override; void dragLeaveEvent(QDragLeaveEvent *) override; void dropEvent(QDropEvent *) override; void mousePressEvent(QMouseEvent *) override; void mouseMoveEvent(QMouseEvent *) override; void mouseReleaseEvent(QMouseEvent *) override; private: class Private; Private *const d; Q_PRIVATE_SLOT(d, void slotAppearanceChanged()) Q_PRIVATE_SLOT(d, void slotContextAboutToShow()) Q_PRIVATE_SLOT(d, void slotContextAboutToHide()) Q_PRIVATE_SLOT(d, void slotContextLeft()) Q_PRIVATE_SLOT(d, void slotContextRight()) Q_PRIVATE_SLOT(d, void slotContextShowText()) Q_PRIVATE_SLOT(d, void slotContextTop()) Q_PRIVATE_SLOT(d, void slotContextBottom()) Q_PRIVATE_SLOT(d, void slotContextIcons()) Q_PRIVATE_SLOT(d, void slotContextText()) Q_PRIVATE_SLOT(d, void slotContextTextRight()) Q_PRIVATE_SLOT(d, void slotContextTextUnder()) Q_PRIVATE_SLOT(d, void slotContextIconSize()) Q_PRIVATE_SLOT(d, void slotLockToolBars(bool)) }; #endif diff --git a/libs/widgetutils/xmlgui/ktoolbarhandler_p.h b/libs/widgetutils/xmlgui/ktoolbarhandler_p.h index 7899b05635..5c5a1bf26c 100644 --- a/libs/widgetutils/xmlgui/ktoolbarhandler_p.h +++ b/libs/widgetutils/xmlgui/ktoolbarhandler_p.h @@ -1,72 +1,72 @@ /* This file is part of the KDE libraries Copyright (C) 2002 Simon Hausmann 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 KTOOLBARHANDLER_H #define KTOOLBARHANDLER_H #include #include #include #include class KXmlGuiWindow; namespace KDEPrivate { class ToolBarHandler : public QObject, public KXMLGUIClient { Q_OBJECT public: /** * Creates a new tool bar handler for the supplied - * @param mainWindow. + * @p mainWindow. */ explicit ToolBarHandler(KXmlGuiWindow *mainWindow); /** * Creates a new tool bar handler for the supplied - * @param mainWindow and with the supplied parent. + * @p mainWindow and with the supplied @p parent. */ ToolBarHandler(KXmlGuiWindow *mainWindow, QObject *parent); /** * Destroys the tool bar handler. */ ~ToolBarHandler() override; /** * Returns the action which is responsible for the tool bar menu. */ QAction *toolBarMenuAction(); public Q_SLOTS: void setupActions(); private: class Private; Private *const d; Q_PRIVATE_SLOT(d, void clientAdded(KXMLGUIClient *)) }; } // namespace KDEPrivate #endif // KTOOLBARHANDLER_H diff --git a/libs/widgetutils/xmlgui/kxmlguibuilder.h b/libs/widgetutils/xmlgui/kxmlguibuilder.h index 274d425238..ca88bd8820 100644 --- a/libs/widgetutils/xmlgui/kxmlguibuilder.h +++ b/libs/widgetutils/xmlgui/kxmlguibuilder.h @@ -1,94 +1,94 @@ /* This file is part of the KDE project Copyright (C) 2000 Simon Hausmann David Faure This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef kxmlguibuilder_h #define kxmlguibuilder_h #include class KXMLGUIBuilderPrivate; class KXMLGUIClient; class QAction; class QDomElement; class QStringList; class QWidget; /** * Implements the creation of the GUI (menubar, menus and toolbars) * as requested by the GUI factory. * * The virtual methods are mostly for historical reasons, there isn't really * a need to derive from KXMLGUIBuilder anymore. */ class KRITAWIDGETUTILS_EXPORT KXMLGUIBuilder { public: explicit KXMLGUIBuilder(QWidget *widget); virtual ~KXMLGUIBuilder(); /* @internal */ KXMLGUIClient *builderClient() const; /* @internal */ void setBuilderClient(KXMLGUIClient *client); /* @internal */ QWidget *widget(); virtual QStringList containerTags() const; /** * Creates a container (menubar/menu/toolbar/statusbar/separator/...) * from an element in the XML file * * @param parent The parent for the container * @param index The index where the container should be inserted * into the parent container/widget * @param element The element from the DOM tree describing the * container (use it to access container specified * attributes or child elements) - * @param action The action created for this container; used for e.g. passing to removeContainer. + * @param containerAction The action created for this container; used for e.g. passing to removeContainer. */ virtual QWidget *createContainer(QWidget *parent, int index, const QDomElement &element, QAction *&containerAction); /** * Removes the given (and previously via createContainer ) * created container. * */ virtual void removeContainer(QWidget *container, QWidget *parent, QDomElement &element, QAction *containerAction); virtual QStringList customTags() const; virtual QAction *createCustomElement(QWidget *parent, int index, const QDomElement &element); virtual void removeCustomElement(QWidget *parent, QAction *action); virtual void finalizeGUI(KXMLGUIClient *client); protected: virtual void virtual_hook(int id, void *data); private: KXMLGUIBuilderPrivate *const d; }; #endif diff --git a/packaging/linux/snap/setup/gui/krita.desktop b/packaging/linux/snap/setup/gui/krita.desktop index af96944042..2d67fb2efe 100755 --- a/packaging/linux/snap/setup/gui/krita.desktop +++ b/packaging/linux/snap/setup/gui/krita.desktop @@ -1,137 +1,138 @@ [Desktop Entry] Name=Krita Name[af]=Krita Name[ar]=كريتا Name[bg]=Krita Name[br]=Krita Name[bs]=Krita Name[ca]=Krita Name[ca@valencia]=Krita Name[cs]=Krita Name[cy]=Krita Name[da]=Krita Name[de]=Krita Name[el]=Krita Name[en_GB]=Krita Name[eo]=Krita Name[es]=Krita Name[et]=Krita Name[eu]=Krita Name[fi]=Krita Name[fr]=Krita Name[fy]=Krita Name[ga]=Krita Name[gl]=Krita Name[he]=Krita Name[hi]=केरिता Name[hne]=केरिता Name[hr]=Krita Name[hu]=Krita Name[ia]=Krita Name[is]=Krita Name[it]=Krita Name[ja]=Krita Name[kk]=Krita Name[ko]=Krita Name[lt]=Krita Name[lv]=Krita Name[mr]=क्रिटा Name[ms]=Krita Name[nb]=Krita Name[nds]=Krita Name[ne]=क्रिता Name[nl]=Krita Name[pl]=Krita Name[pt]=Krita Name[pt_BR]=Krita Name[ro]=Krita Name[ru]=Krita Name[se]=Krita Name[sk]=Krita Name[sl]=Krita Name[sv]=Krita Name[ta]=கிரிட்டா Name[tg]=Krita Name[tr]=Krita Name[ug]=Krita Name[uk]=Krita Name[uz]=Krita Name[uz@cyrillic]=Krita Name[wa]=Krita Name[xh]=Krita Name[x-test]=xxKritaxx Name[zh_CN]=Krita Name[zh_TW]=Krita Exec=krita %F GenericName=Digital Painting GenericName[ar]=رسم رقمي GenericName[bs]=Digitalno Bojenje GenericName[ca]=Dibuix digital GenericName[ca@valencia]=Dibuix digital GenericName[cs]=Digitální malování GenericName[da]=Digital tegning GenericName[de]=Digitales Malen GenericName[el]=Ψηφιακή ζωγραφική GenericName[en_GB]=Digital Painting GenericName[es]=Pintura digital GenericName[et]=Digitaalne joonistamine GenericName[eu]=Margolan digitala GenericName[fi]=Digitaalimaalaus GenericName[fr]=Peinture numérique GenericName[gl]=Debuxo dixital GenericName[hu]=Digitális festészet GenericName[ia]=Pintura Digital GenericName[is]=Stafræn málun GenericName[it]=Pittura digitale GenericName[ja]=デジタルペインティング GenericName[kk]=Цифрлық сурет салу GenericName[lt]=Skaitmeninis piešimas GenericName[mr]=डिजिटल पेंटिंग GenericName[nb]=Digital maling GenericName[nl]=Digitaal schilderen GenericName[pl]=Cyfrowe malowanie GenericName[pt]=Pintura Digital GenericName[pt_BR]=Pintura digital GenericName[ru]=Цифровая живопись GenericName[sk]=Digitálne maľovanie GenericName[sl]=Digitalno slikanje GenericName[sv]=Digital målning GenericName[tr]=Sayısal Boyama GenericName[ug]=سىفىرلىق رەسىم سىزغۇ GenericName[uk]=Цифрове малювання GenericName[x-test]=xxDigital Paintingxx GenericName[zh_CN]=数字绘画 GenericName[zh_TW]=數位繪畫 MimeType=application/x-krita;image/openraster;application/x-krita-paintoppreset; Comment=Pixel-based image manipulation program for the Calligra Suite Comment[ar]=برنامج لتعديل الصور البكسليّة لطقم «كاليغرا» Comment[ca]=Programa de manipulació d'imatges basades en píxels per a la Suite Calligra Comment[ca@valencia]=Programa de manipulació d'imatges basades en píxels per a la Suite Calligra Comment[de]=Pixelbasiertes Bildbearbeitungsprogramm für die Calligra-Suite Comment[el]=Πρόγραμμα επεξεργασίας εικόνας με βάση εικονοστοιχεία για το Calligra Stage Comment[en_GB]=Pixel-based image manipulation program for the Calligra Suite Comment[es]=Programa de manipulación de imágenes basado en píxeles para la suite Calligra Comment[et]=Calligra pikslipõhine pilditöötluse rakendus Comment[eu]=Pixel-oinarridun irudiak manipulatzeko programa Calligra-Suiterako +Comment[fi]=Bittikarttakuvankäsittelyohjelma Calligra-toimisto-ohjelmistoon Comment[gl]=Programa da colección de Calligra para a manipulación de imaxes baseadas en píxeles. Comment[is]=Myndvinnsluforrit fyrir Calligra-forritavöndulinn Comment[it]=Programma di manipolazione delle immagini basato su pixel per Calligra Suite Comment[nl]=Afbeeldingsbewerkingsprogramma gebaseerd op pixels voor de Calligra Suite Comment[pl]=Program do obróbki obrazów na poziomie pikseli dla Pakietu Calligra Comment[pt]='Plugin' de manipulação de imagens em pixels para o Calligra Stage Comment[pt_BR]=Programa de manipulação de imagens baseado em pixels para o Calligra Suite Comment[ru]=Программа редактирования пиксельной анимации для the Calligra Suite Comment[sk]=Program na manipuláciu s pixelmi pre Calligra Suite Comment[sv]=Bildpunktsbaserat bildbehandlingsprogram för Calligra-sviten Comment[tr]=Calligra Suite için Pixel tabanlı görüntü düzenleme programı Comment[uk]=Програма для роботи із растровими зображеннями для комплексу програм Calligra Comment[x-test]=xxPixel-based image manipulation program for the Calligra Suitexx Comment[zh_CN]=Calligra 套件的像素图像处理程序 Comment[zh_TW]=Calligra 套件中基於像素的影像處理程式 Type=Application Icon=${SNAP}/meta/gui/calligrakrita.png Categories=Qt;KDE;Graphics; X-KDE-NativeMimeType=application/x-krita X-KDE-ExtraNativeMimeTypes= StartupNotify=true X-Krita-Version=28 diff --git a/plugins/extensions/buginfo/dlg_buginfo.cpp b/plugins/extensions/buginfo/dlg_buginfo.cpp index 69e7ffc47c..b19dc932a1 100644 --- a/plugins/extensions/buginfo/dlg_buginfo.cpp +++ b/plugins/extensions/buginfo/dlg_buginfo.cpp @@ -1,96 +1,103 @@ /* * Copyright (c) 2017 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 "dlg_buginfo.h" #include #include #include #include #include - +#include #include #include +#include #include "kis_document_aware_spin_box_unit_manager.h" DlgBugInfo::DlgBugInfo(QWidget *parent) : KoDialog(parent) { setCaption(i18n("Please paste this information in your bug report")); setButtons(User1 | Ok); setButtonText(User1, i18n("Copy to clipboard")); setDefaultButton(Ok); m_page = new WdgBugInfo(this); Q_CHECK_PTR(m_page); setMainWidget(m_page); QString info; + // NOTE: This is intentionally not translated! + // Krita version info info.append("Krita"); info.append("\n Version: ").append(KritaVersionWrapper::versionString(true)); info.append("\n\n"); info.append("Qt"); info.append("\n Version (compiled): ").append(QT_VERSION_STR); info.append("\n Version (loaded): ").append(qVersion()); info.append("\n\n"); // OS information info.append("OS Information"); info.append("\n Build ABI: ").append(QSysInfo::buildAbi()); info.append("\n Build CPU: ").append(QSysInfo::buildCpuArchitecture()); info.append("\n CPU: ").append(QSysInfo::currentCpuArchitecture()); info.append("\n Kernel Type: ").append(QSysInfo::kernelType()); info.append("\n Kernel Version: ").append(QSysInfo::kernelVersion()); info.append("\n Pretty Productname: ").append(QSysInfo::prettyProductName()); info.append("\n Product Type: ").append(QSysInfo::productType()); info.append("\n Product Version: ").append(QSysInfo::productVersion()); - info.append("\n"); + info.append("\n\n"); // OpenGL information info.append("\n").append(KisOpenGL::getDebugText()); - - // Installation information + info.append("\n\n"); + // Hardware information + info.append("Hardware Information"); + info.append(QString("\n Memory: %1").arg(KisImageConfig(true).totalRAM() / 1024)).append(" Gb"); + info.append(QString("\n Cores: %1").arg(QThread::idealThreadCount())); + info.append("\n Swap: ").append(KisImageConfig(true).swapDir()); // calculate a default height for the widget int wheight = m_page->sizeHint().height(); m_page->txtBugInfo->setText(info); QFontMetrics fm = m_page->txtBugInfo->fontMetrics(); int target_height = fm.height() * info.split('\n').size() + wheight; QDesktopWidget dw; QRect screen_rect = dw.availableGeometry(dw.primaryScreen()); resize(m_page->size().width(), target_height > screen_rect.height() ? screen_rect.height() : target_height); connect(this, &KoDialog::user1Clicked, this, [this](){ QGuiApplication::clipboard()->setText(m_page->txtBugInfo->toPlainText()); m_page->txtBugInfo->selectAll(); // feedback }); } DlgBugInfo::~DlgBugInfo() { delete m_page; } diff --git a/plugins/extensions/pykrita/plugin/utilities.h b/plugins/extensions/pykrita/plugin/utilities.h index a65d1ff520..2a71d22de7 100644 --- a/plugins/extensions/pykrita/plugin/utilities.h +++ b/plugins/extensions/pykrita/plugin/utilities.h @@ -1,249 +1,251 @@ // This file is part of PyKrita, Krita' Python scripting plugin. // // A couple of useful macros and functions used inside of pykrita_engine.cpp and pykrita_plugin.cpp. // // Copyright (C) 2006 Paul Giannaros // Copyright (C) 2012, 2013 Shaheed Haque // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) version 3, or any // later version accepted by the membership of KDE e.V. (or its // successor approved by the membership of KDE e.V.), which shall // act as a proxy defined in Section 6 of version 3 of the license. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library. If not, see . // #ifndef __PYKRITA_UTILITIES_H__ # define __PYKRITA_UTILITIES_H__ #include #include #include class KConfigBase; /// Save us some ruddy time when printing out QStrings with UTF-8 # define PQ(x) x.toUtf8().constData() class PythonPluginManager; namespace PyKrita { enum InitResult { INIT_UNINITIALIZED, INIT_OK, INIT_CANNOT_LOAD_PYTHON_LIBRARY, INIT_CANNOT_SET_PYTHON_PATHS, INIT_CANNOT_LOAD_PYKRITA_MODULE, }; /** * Initialize the Python environment and plugin manager. * This should be called first before using the manager * or the Python class. */ InitResult initialize(); /** * Gets the instance of the plugin manager. * Note: PyKrita::initialize() must be called * before using this function. */ PythonPluginManager *pluginManager(); /** * Cleanup after Python. * Note: doing this as part of static/global destruction will not * work. The call to Py_Finalize() would happen after the Python * runtime has already been finalized, leading to a segfault. */ void finalize(); /** * Instantiate this class on the stack to automatically get and release the * GIL. * * Also, making all the utility functions members of this class means that in * many cases the compiler tells us where the class in needed. In the remaining * cases (i.e. bare calls to the Python C API), inspection is used to needed * to add the requisite Python() object. To prevent this object being optimised * away in these cases due to lack of use, all instances have the form of an * assignment, e.g.: * * Python py = Python() * * This adds a little overhead, but this is a small price for consistency. */ class Python { public: Python(); ~Python(); /** * Load the Python shared library. This does nothing on Windows. */ static bool libraryLoad(); /** * Set the Python paths by calling Py_SetPath. This should be called before * initialization to ensure the proper libraries get loaded. */ static bool setPath(const QStringList& scriptPaths); /** * Make sure the Python interpreter is initialized. Ideally should be only * called once. */ static void ensureInitialized(); /** * Finalize the Python interpreter. Not guaranteed to work. */ static void maybeFinalize(); /** * Unload the Python shared library. This does nothing on Windows. */ static void libraryUnload(); /// Convert a QString to a Python unicode object. static PyObject* unicode(const QString& string); /// Convert a Python unicode object to a QString. static QString unicode(PyObject* string); /// Test if a Python object is compatible with a QString. static bool isUnicode(PyObject* string); /// Prepend a QString to a list as a Python unicode object bool prependStringToList(PyObject* list, const QString& value); /** * Print and save (see @ref lastTraceback()) the current traceback in a * form approximating what Python would print: * + * @verbatim * Traceback (most recent call last): * File "/home/shahhaqu/.kde/share/apps/krita/pykrita/pluginmgr.py", line 13, in * import kdeui * ImportError: No module named kdeui * Could not import pluginmgr. + * @endverbatim */ void traceback(const QString& description); /** * Store the last traceback we handled using @ref traceback(). */ QString lastTraceback(void) const; /** * Call the named module's named entry point. */ bool functionCall(const char* functionName, const char* moduleName = PYKRITA_ENGINE); PyObject* functionCall(const char* functionName, const char* moduleName, PyObject* arguments); /** * Delete the item from the named module's dictionary. */ bool itemStringDel(const char* item, const char* moduleName = PYKRITA_ENGINE); /** * Get the item from the named module's dictionary. * * @return 0 or a borrowed reference to the item. */ PyObject* itemString(const char* item, const char* moduleName = PYKRITA_ENGINE); /** * Get the item from the given dictionary. * * @return 0 or a borrowed reference to the item. */ PyObject* itemString(const char* item, PyObject* dict); /** * Set the item in the named module's dictionary. */ bool itemStringSet(const char* item, PyObject* value, const char* moduleName = PYKRITA_ENGINE); /** * Get the Actions defined by a module. The returned object is * [ { function, ( text, icon, shortcut, menu ) }... ] for each module - * function decorated with @action. + * function decorated with @c action. * * @return 0 or a new reference to the result. */ PyObject* moduleActions(const char* moduleName); /** * Get the ConfigPages defined by a module. The returned object is * [ { function, callable, ( name, fullName, icon ) }... ] for each module - * function decorated with @configPage. + * function decorated with @c configPage. * * @return 0 or a new reference to the result. */ PyObject* moduleConfigPages(const char* moduleName); /** * Get the named module's dictionary. * * @return 0 or a borrowed reference to the dictionary. */ PyObject* moduleDict(const char* moduleName = PYKRITA_ENGINE); /** * Get the help text defined by a module. */ QString moduleHelp(const char* moduleName); /** * Import the named module. * * @return 0 or a borrowed reference to the module. */ PyObject* moduleImport(const char* moduleName); /** * Add a given path to to the front of \c PYTHONPATH * * @param path A string (path) to be added * @return @c true on success, @c false otherwise. */ bool prependPythonPaths(const QString& path); /** * Add listed paths to to the front of \c PYTHONPATH * * @param paths A string list (paths) to be added * @return @c true on success, @c false otherwise. */ bool prependPythonPaths(const QStringList& paths); static const char* PYKRITA_ENGINE; private: /// @internal Helper function for @c prependPythonPaths overloads bool prependPythonPaths(const QString&, PyObject*); PyGILState_STATE m_state; mutable QString m_traceback; /** * Run a handler function supplied by the krita module on another module. * * @return 0 or a new reference to the result. */ PyObject* kritaHandler(const char* moduleName, const char* handler); }; } // namespace PyKrita #endif // __PYKRITA_UTILITIES_H__ // krita: indent-width 4; diff --git a/plugins/extensions/pykrita/sip/krita/Node.sip b/plugins/extensions/pykrita/sip/krita/Node.sip index 5e726c504e..8a37503f9c 100644 --- a/plugins/extensions/pykrita/sip/krita/Node.sip +++ b/plugins/extensions/pykrita/sip/krita/Node.sip @@ -1,67 +1,68 @@ class Node : QObject { %TypeHeaderCode #include "Node.h" %End Node(const Node & __0); public: virtual ~Node(); bool operator==(const Node &other) const; bool operator!=(const Node &other) const; public Q_SLOTS: //QList shapes() const /Factory/; Node *clone() const /Factory/; bool alphaLocked() const; void setAlphaLocked(bool value); QString blendingMode() const; void setBlendingMode(QString value); QList channels() const /Factory/; QList childNodes() const /Factory/; bool addChildNode(Node *child, Node *above); bool removeChildNode(Node *child); void setChildNodes(QList nodes); QString colorDepth() const; bool animated() const; void enableAnimation() const; void setShowInTimeline(bool showInTimeline) const; bool showInTimeline() const; void setCollapsed(bool collapsed); bool collapsed() const; int colorLabel() const; void setColorLabel(int value); QString colorModel() const; QString colorProfile() const; bool setColorProfile(const QString &colorProfile); bool setColorSpace(const QString &colorModel, const QString &colorDepth, const QString &colorProfile); bool inheritAlpha() const; void setInheritAlpha(bool value); bool locked() const; void setLocked(bool value); QString name() const; void setName(QString value); int opacity() const; void setOpacity(int value); Node * parentNode() const /Factory/; QString type() const; QIcon icon() const; bool visible() const; + bool hasKeyframeAtTime(int frameNumber); void setVisible(bool value); QByteArray pixelData(int x, int y, int w, int h) const; QByteArray pixelDataAtTime(int x, int y, int w, int h, int time) const; QByteArray projectionPixelData(int x, int y, int w, int h) const; void setPixelData(QByteArray value, int x, int y, int w, int h); QRect bounds() const; void move(int x, int y); QPoint position() const; bool remove(); Node *duplicate() /Factory/; void save(const QString &filename, double xRes, double yRes, const InfoObject & exportConfiguration); Node *mergeDown() /Factory/; void scaleNode(QPointF origin, int width, int height, QString strategy); void rotateNode(double radians); void cropNode(int x, int y, int w, int h); void shearNode(double angleX, double angleY); QImage thumbnail(int w, int h); Q_SIGNALS: private: }; diff --git a/plugins/filters/colors/kis_color_to_alpha.cpp b/plugins/filters/colors/kis_color_to_alpha.cpp index 8f1794b05f..b5fdafe079 100644 --- a/plugins/filters/colors/kis_color_to_alpha.cpp +++ b/plugins/filters/colors/kis_color_to_alpha.cpp @@ -1,189 +1,189 @@ /* * This file is part of Krita * * Copyright (c) 2006 Cyrille Berger * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 "kis_color_to_alpha.h" #include #include #include +#include #include #include "kis_progress_update_helper.h" #include #include #include #include #include #include "ui_wdgcolortoalphabase.h" #include "kis_wdg_color_to_alpha.h" #include #include KisFilterColorToAlpha::KisFilterColorToAlpha() : KisFilter(id(), FiltersCategoryColorId, i18n("&Color to Alpha...")) { setSupportsPainting(true); setSupportsAdjustmentLayers(true); setSupportsLevelOfDetail(true); setColorSpaceIndependence(FULLY_INDEPENDENT); } KisConfigWidget * KisFilterColorToAlpha::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP) const { return new KisWdgColorToAlpha(parent); } KisFilterConfigurationSP KisFilterColorToAlpha::factoryConfiguration() const { KisFilterConfigurationSP config = new KisFilterConfiguration("colortoalpha", 1); config->setProperty("targetcolor", QColor(255, 255, 255)); config->setProperty("threshold", 100); return config; } template inline void inverseOver(const int numChannels, const int *channelIndex, channel_type *dst, const channel_type *baseColor, qreal dstOpacity) { for (int i = 0; i < numChannels; i++) { const int idx = channelIndex[i]; dst[idx] = KoColorSpaceMaths::clamp( (static_cast(dst[idx]) - baseColor[idx]) / dstOpacity + baseColor[idx]); } } template void applyToIterator(const int numChannels, const int *channelIndex, KisSequentialIteratorProgress &it, KoColor baseColor, int threshold, const KoColorSpace *cs) { qreal thresholdF = threshold; quint8 *baseColorData_uint8 = baseColor.data(); channel_type *baseColorData = reinterpret_cast(baseColorData_uint8); while (it.nextPixel()) { channel_type *dst = reinterpret_cast(it.rawData()); quint8 *dst_uint8 = it.rawData(); quint8 diff = cs->difference(baseColorData_uint8, dst_uint8); qreal newOpacity = diff >= threshold ? 1.0 : diff / thresholdF; if(newOpacity < cs->opacityF(dst_uint8)) { cs->setOpacity(dst_uint8, newOpacity, 1); } inverseOver(numChannels, channelIndex, dst, baseColorData, newOpacity); } } void KisFilterColorToAlpha::processImpl(KisPaintDeviceSP device, const QRect& rect, const KisFilterConfigurationSP _config, KoUpdater* progressUpdater ) const { Q_ASSERT(device != 0); KisFilterConfigurationSP config = _config ? _config : new KisFilterConfiguration("colortoalpha", 1); QVariant value; QColor cTA = (config->getProperty("targetcolor", value)) ? value.value() : QColor(255, 255, 255); int threshold = (config->getProperty("threshold", value)) ? value.toInt() : 1; const KoColorSpace * cs = device->colorSpace(); KisSequentialIteratorProgress it(device, rect, progressUpdater); KoColor baseColor(cTA, cs); QVector channelIndex; KoChannelInfo::enumChannelValueType valueType = KoChannelInfo::OTHER; QList channels = cs->channels(); for (int i = 0; i < channels.size(); i++) { const KoChannelInfo *info = channels[i]; if (info->channelType() != KoChannelInfo::COLOR) continue; KoChannelInfo::enumChannelValueType currentValueType = info->channelValueType(); if (valueType != KoChannelInfo::OTHER && valueType != currentValueType) { warnKrita << "Cannot apply a Color-to-Alpha filter to a heterogeneous colorspace"; return; } else { valueType = currentValueType; } channelIndex.append(i); } switch (valueType) { case KoChannelInfo::UINT8: applyToIterator(channelIndex.size(), channelIndex.data(), it, baseColor, threshold, cs); break; case KoChannelInfo::UINT16: applyToIterator(channelIndex.size(), channelIndex.data(), it, baseColor, threshold, cs); break; case KoChannelInfo::UINT32: applyToIterator(channelIndex.size(), channelIndex.data(), it, baseColor, threshold, cs); break; case KoChannelInfo::FLOAT32: applyToIterator(channelIndex.size(), channelIndex.data(), it, baseColor, threshold, cs); break; case KoChannelInfo::FLOAT64: applyToIterator(channelIndex.size(), channelIndex.data(), it, baseColor, threshold, cs); break; case KoChannelInfo::FLOAT16: -#include #ifdef HAVE_OPENEXR #include applyToIterator(channelIndex.size(), channelIndex.data(), it, baseColor, threshold, cs); break; #endif case KoChannelInfo::INT8: /* !UNSUPPORTED! */ case KoChannelInfo::INT16: /* !UNSUPPORTED! */ case KoChannelInfo::OTHER: warnKrita << "Color To Alpha: Unsupported channel type:" << valueType; } } diff --git a/plugins/filters/colorsfilters/kis_multichannel_filter_base.cpp b/plugins/filters/colorsfilters/kis_multichannel_filter_base.cpp index 45ebbbb90e..a5385239af 100644 --- a/plugins/filters/colorsfilters/kis_multichannel_filter_base.cpp +++ b/plugins/filters/colorsfilters/kis_multichannel_filter_base.cpp @@ -1,519 +1,521 @@ /* * This file is part of Krita * * Copyright (c) 2018 Jouni Pentikainen * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 "kis_multichannel_filter_base.h" #include #include #include #include #include #include #include #include #include "KoChannelInfo.h" #include "KoBasicHistogramProducers.h" #include "KoColorModelStandardIds.h" #include "KoColorSpace.h" #include "KoColorTransformation.h" #include "KoCompositeColorTransformation.h" #include "KoCompositeOp.h" #include "KoID.h" #include "kis_signals_blocker.h" #include "kis_bookmarked_configuration_manager.h" #include "kis_config_widget.h" #include #include #include #include #include #include "kis_histogram.h" #include "kis_painter.h" #include "widgets/kis_curve_widget.h" KisMultiChannelFilter::KisMultiChannelFilter(const KoID& id, const QString &entry) : KisColorTransformationFilter(id, FiltersCategoryAdjustId, entry) { setSupportsPainting(true); setColorSpaceIndependence(TO_LAB16); } bool KisMultiChannelFilter::needsTransparentPixels(const KisFilterConfigurationSP config, const KoColorSpace *cs) const { Q_UNUSED(config); return cs->colorModelId() == AlphaColorModelID; } QVector KisMultiChannelFilter::getVirtualChannels(const KoColorSpace *cs, int maxChannels) { const bool supportsLightness = cs->colorModelId() != LABAColorModelID && cs->colorModelId() != GrayAColorModelID && cs->colorModelId() != GrayColorModelID && cs->colorModelId() != AlphaColorModelID; const bool supportsHue = supportsLightness; const bool supportSaturation = supportsLightness; QVector vchannels; QList sortedChannels = KoChannelInfo::displayOrderSorted(cs->channels()); if (supportsLightness) { vchannels << VirtualChannelInfo(VirtualChannelInfo::ALL_COLORS, -1, 0, cs); } Q_FOREACH (KoChannelInfo *channel, sortedChannels) { int pixelIndex = KoChannelInfo::displayPositionToChannelIndex(channel->displayPosition(), sortedChannels); vchannels << VirtualChannelInfo(VirtualChannelInfo::REAL, pixelIndex, channel, cs); } if (supportsHue) { vchannels << VirtualChannelInfo(VirtualChannelInfo::HUE, -1, 0, cs); } if (supportSaturation) { vchannels << VirtualChannelInfo(VirtualChannelInfo::SATURATION, -1, 0, cs); } if (supportsLightness) { vchannels << VirtualChannelInfo(VirtualChannelInfo::LIGHTNESS, -1, 0, cs); } if (maxChannels >= 0 && vchannels.size() > maxChannels) { vchannels.resize(maxChannels); } return vchannels; } int KisMultiChannelFilter::findChannel(const QVector &virtualChannels, const VirtualChannelInfo::Type &channelType) { for (int i = 0; i < virtualChannels.size(); i++) { if (virtualChannels[i].type() == channelType) { return i; } } return -1; } KisMultiChannelFilterConfiguration::KisMultiChannelFilterConfiguration(int channelCount, const QString & name, qint32 version) : KisColorTransformationConfiguration(name, version) , m_channelCount(channelCount) { m_transfers.resize(m_channelCount); } KisMultiChannelFilterConfiguration::~KisMultiChannelFilterConfiguration() {} void KisMultiChannelFilterConfiguration::init() { m_curves.clear(); for (int i = 0; i < m_channelCount; ++i) { m_curves.append(getDefaultCurve()); } updateTransfers(); } bool KisMultiChannelFilterConfiguration::isCompatible(const KisPaintDeviceSP dev) const { return (int)dev->compositionSourceColorSpace()->channelCount() == m_channelCount; } void KisMultiChannelFilterConfiguration::setCurves(QList &curves) { m_curves.clear(); m_curves = curves; m_channelCount = curves.size(); updateTransfers(); } void KisMultiChannelFilterConfiguration::updateTransfers() { m_transfers.resize(m_channelCount); for (int i = 0; i < m_channelCount; i++) { m_transfers[i] = m_curves[i].uint16Transfer(); } } const QVector >& KisMultiChannelFilterConfiguration::transfers() const { return m_transfers; } const QList& KisMultiChannelFilterConfiguration::curves() const { return m_curves; } void KisMultiChannelFilterConfiguration::fromLegacyXML(const QDomElement& root) { fromXML(root); } void KisMultiChannelFilterConfiguration::fromXML(const QDomElement& root) { QList curves; quint16 numTransfers = 0; int version; version = root.attribute("version").toInt(); QDomElement e = root.firstChild().toElement(); QString attributeName; KisCubicCurve curve; quint16 index; while (!e.isNull()) { if ((attributeName = e.attribute("name")) == "nTransfers") { numTransfers = e.text().toUShort(); } else { QRegExp rx("curve(\\d+)"); if (rx.indexIn(attributeName, 0) != -1) { index = rx.cap(1).toUShort(); index = qMin(index, quint16(curves.count())); if (!e.text().isEmpty()) { curve.fromString(e.text()); } curves.insert(index, curve); } } e = e.nextSiblingElement(); } //prepend empty curves for the brightness contrast filter. if(getString("legacy") == "brightnesscontrast") { if (getString("colorModel") == LABAColorModelID.id()) { curves.append(KisCubicCurve()); curves.append(KisCubicCurve()); curves.append(KisCubicCurve()); } else { int extraChannels = 5; if (getString("colorModel") == CMYKAColorModelID.id()) { extraChannels = 6; } else if (getString("colorModel") == GrayAColorModelID.id()) { extraChannels = 0; } for(int c = 0; c < extraChannels; c ++) { curves.insert(0, KisCubicCurve()); } } } if (!numTransfers) return; setVersion(version); setCurves(curves); } /** * Inherited from KisPropertiesConfiguration */ //void KisMultiChannelFilterConfiguration::fromXML(const QString& s) void addParamNode(QDomDocument& doc, QDomElement& root, const QString &name, const QString &value) { QDomText text = doc.createTextNode(value); QDomElement t = doc.createElement("param"); t.setAttribute("name", name); t.appendChild(text); root.appendChild(t); } void KisMultiChannelFilterConfiguration::toXML(QDomDocument& doc, QDomElement& root) const { /** + * @code * * 3 * 0,0;0.5,0.5;1,1; * 0,0;1,1; * 0,0;1,1; * + * @endcode */ root.setAttribute("version", version()); QDomText text; QDomElement t; addParamNode(doc, root, "nTransfers", QString::number(m_channelCount)); KisCubicCurve curve; QString paramName; for (int i = 0; i < m_curves.size(); ++i) { QString name = QLatin1String("curve") + QString::number(i); QString value = m_curves[i].toString(); addParamNode(doc, root, name, value); } } KisMultiChannelConfigWidget::KisMultiChannelConfigWidget(QWidget * parent, KisPaintDeviceSP dev, Qt::WindowFlags f) : KisConfigWidget(parent, f) , m_dev(dev) , m_page(new WdgPerChannel(this)) { Q_ASSERT(m_dev); const KoColorSpace *targetColorSpace = dev->compositionSourceColorSpace(); m_virtualChannels = KisMultiChannelFilter::getVirtualChannels(targetColorSpace); } /** * Initialize the dialog. * Note: m_virtualChannels must be populated before calling this */ void KisMultiChannelConfigWidget::init() { QHBoxLayout * layout = new QHBoxLayout(this); Q_CHECK_PTR(layout); layout->setContentsMargins(0,0,0,0); layout->addWidget(m_page); resetCurves(); const int virtualChannelCount = m_virtualChannels.size(); for (int i = 0; i < virtualChannelCount; i++) { const VirtualChannelInfo &info = m_virtualChannels[i]; m_page->cmbChannel->addItem(info.name(), i); } connect(m_page->cmbChannel, SIGNAL(activated(int)), this, SLOT(slotChannelSelected(int))); connect((QObject*)(m_page->chkLogarithmic), SIGNAL(toggled(bool)), this, SLOT(logHistView())); connect((QObject*)(m_page->resetButton), SIGNAL(clicked()), this, SLOT(resetCurve())); // create the horizontal and vertical gradient labels m_page->hgradient->setPixmap(createGradient(Qt::Horizontal)); m_page->vgradient->setPixmap(createGradient(Qt::Vertical)); // init histogram calculator const KoColorSpace *targetColorSpace = m_dev->compositionSourceColorSpace(); QList keys = KoHistogramProducerFactoryRegistry::instance()->keysCompatibleWith(targetColorSpace); if (keys.size() > 0) { KoHistogramProducerFactory *hpf; hpf = KoHistogramProducerFactoryRegistry::instance()->get(keys.at(0)); m_histogram = new KisHistogram(m_dev, m_dev->exactBounds(), hpf->generate(), LINEAR); } connect(m_page->curveWidget, SIGNAL(modified()), this, SIGNAL(sigConfigurationItemChanged())); { KisSignalsBlocker b(m_page->curveWidget); m_page->curveWidget->setCurve(m_curves[0]); setActiveChannel(0); } } KisMultiChannelConfigWidget::~KisMultiChannelConfigWidget() { delete m_histogram; } void KisMultiChannelConfigWidget::resetCurves() { const KisPropertiesConfigurationSP &defaultConfiguration = getDefaultConfiguration(); const auto *defaults = dynamic_cast(defaultConfiguration.data()); KIS_SAFE_ASSERT_RECOVER_RETURN(defaults); m_curves = defaults->curves(); const int virtualChannelCount = m_virtualChannels.size(); for (int i = 0; i < virtualChannelCount; i++) { const VirtualChannelInfo &info = m_virtualChannels[i]; m_curves[i].setName(info.name()); } } void KisMultiChannelConfigWidget::setConfiguration(const KisPropertiesConfigurationSP config) { const KisMultiChannelFilterConfiguration * cfg = dynamic_cast(config.data()); if (!cfg) { return; } if (cfg->curves().empty()) { /** * HACK ALERT: our configuration factory generates * default configuration with nTransfers==0. * Catching it here. Just set everything to defaults instead. */ const KisPropertiesConfigurationSP &defaultConfiguration = getDefaultConfiguration(); const auto *defaults = dynamic_cast(defaultConfiguration.data()); KIS_SAFE_ASSERT_RECOVER_RETURN(defaults); if (!defaults->curves().isEmpty()) { setConfiguration(defaultConfiguration); return; } } else if (cfg->curves().size() > m_virtualChannels.size()) { warnKrita << "WARNING: trying to load a curve with invalid number of channels!"; warnKrita << "WARNING: expected:" << m_virtualChannels.size(); warnKrita << "WARNING: got:" << cfg->curves().size(); return; } else { if (cfg->curves().size() < m_virtualChannels.size()) { // The configuration does not cover all our channels. // This happens when loading a document from an older version, which supported fewer channels. // Reset to make sure the unspecified channels have their default values. resetCurves(); } for (int ch = 0; ch < cfg->curves().size(); ch++) { m_curves[ch] = cfg->curves()[ch]; } } // HACK: we save the previous curve in setActiveChannel, so just copy it m_page->curveWidget->setCurve(m_curves[m_activeVChannel]); setActiveChannel(0); } inline QPixmap KisMultiChannelConfigWidget::createGradient(Qt::Orientation orient /*, int invert (not used yet) */) { int width; int height; int *i, inc, col; int x = 0, y = 0; if (orient == Qt::Horizontal) { i = &x; inc = 1; col = 0; width = 256; height = 1; } else { i = &y; inc = -1; col = 255; width = 1; height = 256; } QPixmap gradientpix(width, height); QPainter p(&gradientpix); p.setPen(QPen(QColor(0, 0, 0), 1, Qt::SolidLine)); for (; *i < 256; (*i)++, col += inc) { p.setPen(QColor(col, col, col)); p.drawPoint(x, y); } return gradientpix; } inline QPixmap KisMultiChannelConfigWidget::getHistogram() { int i; int height = 256; QPixmap pix(256, height); KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_histogram, pix); bool logarithmic = m_page->chkLogarithmic->isChecked(); if (logarithmic) m_histogram->setHistogramType(LOGARITHMIC); else m_histogram->setHistogramType(LINEAR); QPalette appPalette = QApplication::palette(); pix.fill(QColor(appPalette.color(QPalette::Base))); QPainter p(&pix); p.setPen(QColor(appPalette.color(QPalette::Text))); p.save(); p.setOpacity(0.2); const VirtualChannelInfo &info = m_virtualChannels[m_activeVChannel]; if (info.type() == VirtualChannelInfo::REAL) { m_histogram->setChannel(info.pixelIndex()); double highest = (double)m_histogram->calculations().getHighest(); qint32 bins = m_histogram->producer()->numberOfBins(); if (m_histogram->getHistogramType() == LINEAR) { double factor = (double)height / highest; for (i = 0; i < bins; ++i) { p.drawLine(i, height, i, height - int(m_histogram->getValue(i) * factor)); } } else { double factor = (double)height / (double)log(highest); for (i = 0; i < bins; ++i) { p.drawLine(i, height, i, height - int(log((double)m_histogram->getValue(i)) * factor)); } } } p.restore(); return pix; } void KisMultiChannelConfigWidget::slotChannelSelected(int index) { const int virtualChannel = m_page->cmbChannel->itemData(index).toInt(); setActiveChannel(virtualChannel); } void KisMultiChannelConfigWidget::setActiveChannel(int ch) { m_curves[m_activeVChannel] = m_page->curveWidget->curve(); m_activeVChannel = ch; m_page->curveWidget->setCurve(m_curves[m_activeVChannel]); m_page->curveWidget->setPixmap(getHistogram()); const int index = m_page->cmbChannel->findData(m_activeVChannel); m_page->cmbChannel->setCurrentIndex(index); updateChannelControls(); } void KisMultiChannelConfigWidget::logHistView() { m_page->curveWidget->setPixmap(getHistogram()); } void KisMultiChannelConfigWidget::resetCurve() { const KisPropertiesConfigurationSP &defaultConfiguration = getDefaultConfiguration(); const auto *defaults = dynamic_cast(defaultConfiguration.data()); KIS_SAFE_ASSERT_RECOVER_RETURN(defaults); auto defaultCurves = defaults->curves(); KIS_SAFE_ASSERT_RECOVER_RETURN(defaultCurves.size() > m_activeVChannel); m_page->curveWidget->setCurve(defaultCurves[m_activeVChannel]); } diff --git a/plugins/flake/textshape/kotext/KoAnchorInlineObject.h b/plugins/flake/textshape/kotext/KoAnchorInlineObject.h index 6627ed228c..e2a3bea8ff 100644 --- a/plugins/flake/textshape/kotext/KoAnchorInlineObject.h +++ b/plugins/flake/textshape/kotext/KoAnchorInlineObject.h @@ -1,99 +1,101 @@ /* This file is part of the KDE project * Copyright (C) 2007, 2009 Thomas Zander * Copyright (C) 2011 Matus Hanzes * Copyright (C) 2013 C. Boemann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOANCHORINLINEOBJECT_H #define KOANCHORINLINEOBJECT_H #include "KoInlineObject.h" #include "KoShapeAnchor.h" #include "kritatext_export.h" class KoAnchorInlineObjectPrivate; /** * This class connects KoShapeAnchor to an inline character in the text document. * * This class is used when the shape anchor is of type: as-char * * It has to be registered to the inlineobjectmanager and thus forms the connection between the text * and the KoShapeAnchor and by extension the so called 'anchored-shape' (any kind of shape) * * The KoAnchorInlineObject is placed as a character in text. As such it will move and be * editable like any other character, including deletion. * * Since this is a real character it will be positioned by the textlayout engine and anything that * will change the position of the text will thus also change the KoAnchorInlineObject character. * * The anchored-shape can be repositioned on the canvas if the text is relayouted (for example after * editing the text. This is dependent on how the text layout is implemented. * - * Steps to use a KoAnchorInlineObject are;
    + * Steps to use a KoAnchorInlineObject are + *
      *
    1. Create KoShapeAnchor *anchor = new KoShapeAnchor(shape); *
    2. Use anchor->loadOdf() to load additional attributes like the "text:anchor-type" *
    3. if type is as-char create KoAnchorInlineObject *anchorObj = new KoAnchorInlineObject(anchor); + *
    */ class KRITATEXT_EXPORT KoAnchorInlineObject : public KoInlineObject, public KoShapeAnchor::TextLocation { Q_OBJECT public: /** * Constructor for an as-char anchor. * @param parent the shapeanchor. */ explicit KoAnchorInlineObject(KoShapeAnchor *parent); ~KoAnchorInlineObject() override; /// returns the parent anchor KoShapeAnchor *anchor() const; /// returns the cursor position in the document where this anchor is positioned. int position() const override; /// returns the document that this anchor is associated with. const QTextDocument *document() const override; /// reimplemented from KoInlineObject void updatePosition(const QTextDocument *document, int posInDocument, const QTextCharFormat &format) override; /// reimplemented from KoInlineObject void resize(const QTextDocument *document, QTextInlineObject &object, int posInDocument, const QTextCharFormat &format, QPaintDevice *pd) override; /// reimplemented from KoInlineObject void paint(QPainter &painter, QPaintDevice *pd, const QTextDocument *document, const QRectF &rect, const QTextInlineObject &object, int posInDocument, const QTextCharFormat &format) override; qreal inlineObjectAscent() const; qreal inlineObjectDescent() const; /// reimplemented from KoInlineObject - should not do anything bool loadOdf(const KoXmlElement &, KoShapeLoadingContext &) override; /// reimplemented from KoInlineObject void saveOdf(KoShapeSavingContext &context) override; private: Q_DECLARE_PRIVATE(KoAnchorInlineObject) }; #endif diff --git a/plugins/flake/textshape/kotext/KoAnchorTextRange.h b/plugins/flake/textshape/kotext/KoAnchorTextRange.h index f7528884a4..35b441680c 100644 --- a/plugins/flake/textshape/kotext/KoAnchorTextRange.h +++ b/plugins/flake/textshape/kotext/KoAnchorTextRange.h @@ -1,86 +1,89 @@ /* This file is part of the KDE project * Copyright (C) 2007, 2009 Thomas Zander * Copyright (C) 2011 Matus Hanzes * Copyright (C) 2013 C. Boemann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOANCHORTEXTRANGE_H #define KOANCHORTEXTRANGE_H #include "KoTextRange.h" #include "KoShapeAnchor.h" #include "kritatext_export.h" class KoAnchorTextRangePrivate; class QTextCursor; /** * This class connects KoShapeAnchor to a position in the text document. * * This class is used when the shape anchor is of type: char or paragraph * * It has to be registered to the textrange manager and thus forms the connection between the text * and the KoShapeAnchor and by extension the so called 'anchored-shape' (any kind of shape) * * The KoAnchorTextRange is placed at a position in text. As with all KoTextRange it will change * it's position in the text when the user edits text before it. The user is also able to delete it if * deleting the text where it is positioned. * * The anchored-shape can be repositioned on the canvas if the text is relayouted (for example after * editing the text. This is dependent on how the text layout is implemented. * - * Steps to use a KoAnchorTextRange are;
      + * Steps to use a KoAnchorTextRange are + *
        *
      1. Create KoShapeAnchor *anchor = new KoShapeAnchor(shape); *
      2. Use anchor->loadOdf() to load additional attributes like the "text:anchor-type" *
      3. if type is char or paragraph create KoAnchorTextRange *anchorRange = new KoAnchorTextRange(anchor); + *
      */ class KRITATEXT_EXPORT KoAnchorTextRange : public KoTextRange, public KoShapeAnchor::TextLocation { Q_OBJECT public: /** * Constructor for a char or paragraph anchor. - * @param parent the shapeanchor. + * @param parent the shape anchor. + * @param cursor the text cursor. */ KoAnchorTextRange(KoShapeAnchor *parent, const QTextCursor &cursor); ~KoAnchorTextRange() override; /// returns the parent anchor KoShapeAnchor *anchor() const; /// reimplemented from KoShapeAnchor::TextLocation const QTextDocument *document() const override; /// reimplemented from KoShapeAnchor::TextLocation int position() const override; void updateContainerModel(); /// reimplemented from KoTextRange - should not do anything bool loadOdf(const KoXmlElement &, KoShapeLoadingContext &) override; /// reimplemented from KoTextRange void saveOdf(KoShapeSavingContext &context, int position, KoTextRange::TagType tagType) const override; private: KoAnchorTextRangePrivate * const d_ptr; Q_DECLARE_PRIVATE(KoAnchorTextRange) }; #endif diff --git a/plugins/flake/textshape/kotext/KoAnnotationManager.h b/plugins/flake/textshape/kotext/KoAnnotationManager.h index accb285011..9d3df698a2 100644 --- a/plugins/flake/textshape/kotext/KoAnnotationManager.h +++ b/plugins/flake/textshape/kotext/KoAnnotationManager.h @@ -1,81 +1,81 @@ /* This file is part of the KDE project * Copyright (C) 2007 Fredy Yanardi * Copyright (C) 2012 Inge Wallin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOANNOTATIONMANAGER_H #define KOANNOTATIONMANAGER_H #include "kritatext_export.h" #include #include class KoAnnotation; class KoAnnotationManagerPrivate; /** * A manager for all annotations in a document. Every annotation is identified by a unique name. * Note that only SinglePosition and StartAnnotation annotations can be retrieved from this * manager. An end annotation should be retrieved from it's parent (StartAnnotation) using * KoAnnotation::endAnnotation() * This class also maintains a list of annotation names so that it can be easily used to * show all available annotation. */ class KRITATEXT_EXPORT KoAnnotationManager : public QObject { Q_OBJECT public: /// constructor KoAnnotationManager(); ~KoAnnotationManager() override; /// @return an annotation with the specified name, or 0 if there is none KoAnnotation *annotation(const QString &name) const; /// @return a list of QString containing all annotation names QList annotationNameList() const; public Q_SLOTS: /** * Insert a new annotation to this manager. The name of the annotation - * will be set to @param name, no matter what name has been set on + * will be set to @p name, no matter what name has been set on * it. * @param name the name of the annotation * @param annotation the annotation object to insert */ void insert(const QString &name, KoAnnotation *annotation); /** * Remove an annotation from this manager. * @param name the name of the annotation to remove */ void remove(const QString &name); /** * Rename an annotation * @param oldName the old name of the annotation * @param newName the new name of the annotation */ void rename(const QString &oldName, const QString &newName); private: KoAnnotationManagerPrivate * const d; }; #endif diff --git a/plugins/flake/textshape/kotext/KoBookmarkManager.h b/plugins/flake/textshape/kotext/KoBookmarkManager.h index 2e85445f63..5ec4a2efde 100644 --- a/plugins/flake/textshape/kotext/KoBookmarkManager.h +++ b/plugins/flake/textshape/kotext/KoBookmarkManager.h @@ -1,82 +1,82 @@ /* This file is part of the KDE project * Copyright (C) 2007 Fredy Yanardi * Copyright (C) 2012 C. Boemann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOBOOKMARKMANAGER_H #define KOBOOKMARKMANAGER_H #include "kritatext_export.h" #include #include #include class KoBookmark; class KoBookmarkManagerPrivate; /** * A manager for all bookmarks in a document. Every bookmark is identified by a unique name. * Note that only SinglePosition and StartBookmark bookmarks can be retrieved from this * manager. An end bookmark should be retrieved from it's parent (StartBookmark) using * KoBookmark::endBookmark() * This class also maintains a list of bookmark names so that it can be easily used to * show all available bookmark. */ class KRITATEXT_EXPORT KoBookmarkManager : public QObject { Q_OBJECT public: /// constructor KoBookmarkManager(); ~KoBookmarkManager() override; /// @return a bookmark with the specified name, or 0 if there is none KoBookmark *bookmark(const QString &name) const; /// @return a list of QString containing all bookmark names QList bookmarkNameList() const; public Q_SLOTS: /** * Insert a new bookmark to this manager. The name of the bookmark - * will be set to @param name, no matter what name has been set on + * will be set to @p name, no matter what name has been set on * it. * @param name the name of the bookmark * @param bookmark the bookmark object to insert */ void insert(const QString &name, KoBookmark *bookmark); /** * Remove a bookmark from this manager. * @param name the name of the bookmark to remove */ void remove(const QString &name); /** * Rename a bookmark * @param oldName the old name of the bookmark * @param newName the new name of the bookmark */ void rename(const QString &oldName, const QString &newName); private: KoBookmarkManagerPrivate * const d; }; #endif diff --git a/plugins/flake/textshape/kotext/KoDocumentRdfBase.h b/plugins/flake/textshape/kotext/KoDocumentRdfBase.h index 96a737cc56..8549d44346 100644 --- a/plugins/flake/textshape/kotext/KoDocumentRdfBase.h +++ b/plugins/flake/textshape/kotext/KoDocumentRdfBase.h @@ -1,95 +1,95 @@ /* This file is part of the KDE project Copyright (C) 2010 KO GmbH This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KO_DOCUMENT_Rdf_Base_H #define KO_DOCUMENT_Rdf_Base_H #include "kritatext_export.h" #include #include #include #include #include #include class KoDocumentResourceManager; class QTextDocument; class KoStore; class KoXmlWriter; ///** // * Dummy definition in case Soprano is not available. // */ namespace Soprano { class Model; } /** * A base class that provides the interface to many RDF features * but will not do anything if Soprano support is not built. * By having this "Base" class, code can call methods at points - * where RDF handling is desired and can avoid #ifdef conditionals + * where RDF handling is desired and can avoid \#ifdef conditionals * because the base class interface is here and will be valid, even * if impotent when Soprano support is not built. */ class KRITATEXT_EXPORT KoDocumentRdfBase : public QObject, public KoDataCenterBase { Q_OBJECT public: explicit KoDocumentRdfBase(QObject *parent = 0); ~KoDocumentRdfBase() override; /** * Get the Soprano::Model that contains all the Rdf * You do not own the model, do not delete it. */ #ifdef SHOULD_BUILD_RDF virtual QSharedPointer model() const; #endif virtual void linkToResourceManager(KoDocumentResourceManager *rm); virtual void updateInlineRdfStatements(const QTextDocument *qdoc); virtual void updateXmlIdReferences(const QMap &m); /** * idrefList queries soprano after loading and creates a list of all rdfid's that * where found in the manifest.rdf document. This list is used to make sure we do not * create more inline rdf objects than necessary * @return a list of xml-id's */ virtual QStringList idrefList() const; virtual bool loadOasis(KoStore *store); virtual bool saveOasis(KoStore *store, KoXmlWriter *manifestWriter); // reimplemented in komain/rdf/KoDocumentRdf bool completeLoading(KoStore *store) override; bool completeSaving(KoStore *store, KoXmlWriter *manifestWriter, KoShapeSavingContext *context) override; }; Q_DECLARE_METATYPE(KoDocumentRdfBase*) #endif diff --git a/plugins/flake/textshape/kotext/KoInlineObjectFactoryBase.h b/plugins/flake/textshape/kotext/KoInlineObjectFactoryBase.h index 755d0ea726..0dd1339ac0 100644 --- a/plugins/flake/textshape/kotext/KoInlineObjectFactoryBase.h +++ b/plugins/flake/textshape/kotext/KoInlineObjectFactoryBase.h @@ -1,107 +1,107 @@ /* This file is part of the KDE project * Copyright (C) 2006 Thomas Zander * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOINLINEOBJECTFACTORY_H #define KOINLINEOBJECTFACTORY_H #include #include "kritatext_export.h" class KoInlineObject; class InlineObjectFactoryPrivate; class KoProperties; /// A template used in the KoInlineObjectFactoryBase struct KRITATEXT_EXPORT KoInlineObjectTemplate { QString id; ///< The id of the inlineObject QString name; ///< The name to be shown for this template /** * The properties which, when passed to the KoInlineObjectFactoryBase::createInlineObject() method * result in the object this template represents. */ const KoProperties *properties; }; /** * A factory for inline text objects. There should be one for each plugin type to * allow the creation of the inlineObject from that plugin. * The factory additionally has information to allow showing a menu entry for user * access to the object-type. * @see KoInlineObjectRegistry */ class KRITATEXT_EXPORT KoInlineObjectFactoryBase { public: /// The type of inlineObject this factory creates. enum ObjectType { TextVariable, ///< The factory creates KoVariable inherting objects. Other = 0x100 ///< The factory creates objects that should not be shown in any menu }; /** * Create the new factory - * @param parent the parent QObject for memory management usage. * @param id a string that will be used internally for referencing the variable-type. + * @param type the object type for the new factory. */ KoInlineObjectFactoryBase(const QString &id, ObjectType type); virtual ~KoInlineObjectFactoryBase(); /** * Create a new instance of an inline object. */ virtual KoInlineObject *createInlineObject(const KoProperties *properties = 0) const = 0; /** * return the id for the variable this factory creates. * @return the id for the variable this factory creates. */ QString id() const; /** * Returns the type of object this factory creates. * The main purpose is to group plugins per type in, for example, a menu. */ ObjectType type() const; /** * Return all the templates this factory knows about. * Each template shows a different way to create an object this factory is specialized in. */ QList templates() const; QStringList odfElementNames() const; QString odfNameSpace() const; void setOdfElementNames(const QString &nameSpace, const QStringList &names); protected: /** * Add a template with the properties of a specific type of object this factory can generate * using the createInlineObject() method. * @param params The new template this factory knows to produce */ void addTemplate(const KoInlineObjectTemplate ¶ms); private: InlineObjectFactoryPrivate * const d; }; #endif diff --git a/plugins/flake/textshape/kotext/KoInlineTextObjectManager.h b/plugins/flake/textshape/kotext/KoInlineTextObjectManager.h index 75500f0d24..64f1c83bb9 100644 --- a/plugins/flake/textshape/kotext/KoInlineTextObjectManager.h +++ b/plugins/flake/textshape/kotext/KoInlineTextObjectManager.h @@ -1,186 +1,186 @@ /* This file is part of the KDE project * Copyright (C) 2006-2009 Thomas Zander * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOINLINETEXTOBJECTMANAGER_H #define KOINLINETEXTOBJECTMANAGER_H #include "KoInlineObject.h" #include "KoVariableManager.h" #include "kritatext_export.h" // Qt + kde #include #include class KoCanvasBase; class KoTextLocator; class KoInlineNote; class KoInlineCite; class QTextCharFormat; class QAction; /** * A container to register all the inlineTextObjects with. * Inserting an inline-object in a QTextDocument should be done via this manager which will * insert a placeholder in the text and you should add the KoInlineTextObjectManager to the * KoTextDocument. */ class KRITATEXT_EXPORT KoInlineTextObjectManager : public QObject { Q_OBJECT public: enum Properties { InlineInstanceId = 577297549 // If you change this, don't forget to change KoCharacterStyle.h }; /// Constructor explicit KoInlineTextObjectManager(QObject *parent = 0); ~KoInlineTextObjectManager() override; /** * Retrieve a formerly added inline object based on the format. * @param format the textCharFormat */ KoInlineObject *inlineTextObject(const QTextCharFormat &format) const; /** * Retrieve a formerly added inline object based on the cursor position. * @param cursor the cursor which position is used. The anchor is ignored. */ KoInlineObject *inlineTextObject(const QTextCursor &cursor) const; /** * Retrieve a formerly added inline object based on the KoInlineObject::id() of the object. * @param id the id assigned to the inline text object when it was added. */ KoInlineObject *inlineTextObject(int id) const; QList inlineTextObjects() const; /** * Insert a new inline object into the manager as well as the document. * This method will cause a placeholder to be inserted into the text at cursor position, * possibly replacing a selection. The object will then be used as an inline * character and painted at the specified location in the text. * @param cursor the cursor which indicated the document and the position in that document * where the inline object will be inserted. * @param object the inline object to insert. */ void insertInlineObject(QTextCursor &cursor, KoInlineObject *object); /** * Add inline object into the manager. * * This methods add the inline object into the manager. This is useful if you have a command * that removes and adds a inline object to the manager. If the object already was inserted before * (the object id is already set) it keeps the old id, otherwise a new id will be generated. * * @param object the inline object to insert. */ void addInlineObject(KoInlineObject* object); /** * Remove an inline object from this manager. The object will also be removed from * the bookmarkmanager if it is a bookmark. This is not done smart: you might end up * with dangling start or end bookmarks. * Should really only be called by KoTextEditor's delete commands - * @param the object to be removed + * @param object the object to be removed */ void removeInlineObject(KoInlineObject *object); /** * Set a property that may have changed which will be forwarded to all registered textObjects. * If the key has changed then all registered InlineObject instances that have stated to want * updates will get called with the change. * The property will be stored to allow it to be retrieved via the intProperty() and friends. * @see KoInlineObject::propertyChangeListener() */ void setProperty(KoInlineObject::Property key, const QVariant &value); /// retrieve a property QVariant property(KoInlineObject::Property key) const; /// retrieve an int property int intProperty(KoInlineObject::Property key) const; /// retrieve a bool property bool boolProperty(KoInlineObject::Property key) const; /// retrieve a string property QString stringProperty(KoInlineObject::Property key) const; /// remove a property from the store. void removeProperty(KoInlineObject::Property key); /** * Return the variableManager. */ const KoVariableManager *variableManager() const; /** * Return the variableManager. */ KoVariableManager *variableManager(); /** * Create a list of actions that can be used to plug into a menu, for example. * This method internally uses KoInlineObjectRegistry::createInsertVariableActions() but extends * the list with all registered variable-names. * Each of these actions, when executed, will insert the relevant variable in the current text-position. * The actions assume that the text tool is selected, if that's not the case then they will silently fail. * @param host the canvas for which these actions are created. Note that the actions will get these * actions as a parent (for memory management purposes) as well. * @see KoVariableManager */ QList createInsertVariableActions(KoCanvasBase *host) const; QList textLocators() const; /** * It returns a list of all end notes in the document */ QList endNotes() const; QMap citations(bool duplicatesEnabled = true) const; QList citationsSortedByPosition(bool duplicatesEnabled = true, QTextBlock block = QTextBlock()) const; public Q_SLOTS: void documentInformationUpdated(const QString &info, const QString &data); Q_SIGNALS: /** * Emitted whenever a property is set and it turns out to be changed. */ void propertyChanged(int, const QVariant &variant); private: void insertObject(KoInlineObject *object); QHash m_objects; QHash m_deletedObjects; QList m_listeners; // holds objects also in m_objects, but which want propertyChanges int m_lastObjectId; QHash m_properties; KoVariableManager m_variableManager; }; Q_DECLARE_METATYPE(KoInlineTextObjectManager*) #endif diff --git a/plugins/flake/textshape/kotext/KoSectionModel.h b/plugins/flake/textshape/kotext/KoSectionModel.h index 700c03ca46..438622472b 100644 --- a/plugins/flake/textshape/kotext/KoSectionModel.h +++ b/plugins/flake/textshape/kotext/KoSectionModel.h @@ -1,142 +1,144 @@ #ifndef KOSECTIONMODEL_H #define KOSECTIONMODEL_H #include #include #include #include #include #include /** * Used to handle all the sections in the document * * Now there actually two levels of section handling: * 1) Formatting Level: on this level we should be sure, that * pointers to KoSection and KoSectionEnd in the KoParagraphStyles * properties SectionEndings and SectionStartings are consistent. * Handling on this level is provided on the level of text editing * commands: DeleteCommand, NewSectionCommand * We can't move it to another place, because we should know the * semantics of operation to handle it right way. * 2) Model(Tree) Level: on this level we should update KoSectionModel * right way, so it in any moment represents the actual tree * of sections. Tree is built easily: * One section is son of another, if it is directly nested in it. * As text editing commands have access to change Formatting Level, * they are declared as friend classes of KoSectionModel to be able * affect Model structure without changing something on Formatting * Level. Also affected by RenameSectionCommand. * * Also we need to look at the consistency of some section properties: * * 1) Bounds. Those now are handled with QTextCursors that are placed * on start and end of the section. In default state start cursor * isn't moving if text inserted in its position, and end cursor * moves. But in the case of initial document loading, it is necessary * to make some end cursors stop moving, so we have: * KoTextLoader -> calling -> KoSection::setKeepEndBound() * KoTextLoader -> calling -> KoSectionModel::allowMovingEndBound() * ^-- this needed to restore default behaviour after load * * 2) Level. Level means the depth of the section in tree. Root * sections has 0 (zero) level. Now if you look at the possible * text editing command affecting sections you may notice that * level of section doesn't change in any case. Initial level * is set in KoSection constructor as parent's level plus one. * TODO: write about drag-n-drop here, when its implemented * * 3) Name. Each KoSection has a name that must be unique. We have * two groups of KoSections in each moment of time: the first group * consists of the sections that are present in document now, * the second group consists of the sections that were deleted, but * we still need them as they may be restored with "undo". * This groups are stored in m_registeredSections and m_sectionNames. * * Sections are created through this newSection() and newSectionEnd() * functions. * * This object is created for QTextDocument on the first query of it. */ class KRITATEXT_EXPORT KoSectionModel : public QAbstractItemModel { Q_OBJECT public: static const int PointerRole = Qt::UserRole; explicit KoSectionModel(QTextDocument *doc); ~KoSectionModel() override; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex &child) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - /// Creates KoSection in position of @param cursor with some allowed name + /// Creates KoSection in position of @p cursor with some allowed name KoSection *createSection(const QTextCursor &cursor, KoSection *parent); - /// Creates KoSection in position of @param cursor with specified @param name + /// Creates KoSection in position of @p cursor with specified @p name KoSection *createSection(const QTextCursor &cursor, KoSection *parent, const QString &name); - /// Creates KoSectionEnd in pair for a @param section + /// Creates KoSectionEnd in pair for a @p section KoSectionEnd *createSectionEnd(KoSection *section); - /** Tries to set @param section name to @param name + /** Tries to set @p section name to @p name * @return @c false if there is a section with such name * and new name isn't accepted and @c true otherwise. */ bool setName(KoSection *section, const QString &name); /** * Returns pointer to the deepest KoSection that covers @p pos * or 0 if there is no such section */ KoSection *sectionAtPosition(int pos); /// Returns name for the new section. QString possibleNewName(); /// Returns if this name is possible. bool isValidNewName(const QString &name) const; /// Setting all sections end bound cursor to move with text inserting. void allowMovingEndBound(); - /// Finds index of @param child inside his parent. + /// Finds index of @p child inside his parent. int findRowOfChild(KoSection *child) const; private: Q_DISABLE_COPY(KoSectionModel) friend class DeleteCommand; friend class NewSectionCommand; /** - * Inserts @param section to it's parent (should be - * stored in @param section already) in position childIdx. - * Affects only Model Level(@see KoSectionModel). + * Inserts @p section to it's parent (should be + * stored in @p section already) in position childIdx. + * Affects only Model Level + * @see KoSectionModel */ void insertToModel(KoSection* section, int childIdx); /** - * Deletes @param section from it's parent (should be - * stored in @param section already). - * Affects only Model Level(@see KoSectionModel). + * Deletes @p section from it's parent (should be + * stored in @p section already). + * Affects only Model Level + * @see KoSectionModel */ void deleteFromModel(KoSection *section); QTextDocument *m_doc; QSet m_registeredSections; ///< stores pointer to sections that sometime was registered QHash m_sectionNames; ///< stores name -> pointer reference, for sections that are visible in document now QHash m_modelIndex; QVector m_rootSections; }; Q_DECLARE_METATYPE(KoSectionModel *) #endif //KOSECTIONMODEL_H diff --git a/plugins/flake/textshape/kotext/KoText.h b/plugins/flake/textshape/kotext/KoText.h index 2f89bbef61..f549b58f93 100644 --- a/plugins/flake/textshape/kotext/KoText.h +++ b/plugins/flake/textshape/kotext/KoText.h @@ -1,131 +1,131 @@ /* This file is part of the KDE project * Copyright (C) 2006, 2010 Thomas Zander * Copyright (C) 2008 Girish Ramakrishnan * Copyright (C) 2011 Pierre Ducroquet * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOTEXT_H #define KOTEXT_H #include "kritatext_export.h" #include #include #include #include #include class QStringList; /** * Generic namespace of the Calligra Text library for helper methods and data. */ namespace KoText { KRITATEXT_EXPORT QStringList underlineTypeList(); KRITATEXT_EXPORT QStringList underlineStyleList(); KRITATEXT_EXPORT Qt::Alignment alignmentFromString(const QString &align); KRITATEXT_EXPORT QString alignmentToString(Qt::Alignment align); KRITATEXT_EXPORT Qt::Alignment valignmentFromString(const QString &align); KRITATEXT_EXPORT QString valignmentToString(Qt::Alignment align); /// This enum contains values to be used as keys in KoCanvasResourceProvider enum CanvasResource { CurrentTextDocument = 382490375, ///< set by the text plugin whenever the document is changed CurrentTextPosition = 183523, ///< used by the text plugin whenever the position is changed CurrentTextAnchor = 341899485, ///< used by the text plugin whenever the anchor-position is changed SelectedTextPosition = 21314576, ///< used by the text plugin whenever the alternative selection is changed /// used by the text plugin whenever the alternative selection anchor-position is changed SelectedTextAnchor = 3344189 }; /// For paragraphs each tab definition is represented by this struct. struct KRITATEXT_EXPORT Tab { Tab(); qreal position; ///< distance in ps-points from the edge of the text-shape QTextOption::TabType type; ///< Determine which type is used. QChar delimiter; ///< If type is DelimitorTab; tab until this char was found in the text. KoCharacterStyle::LineType leaderType; // none/single/double KoCharacterStyle::LineStyle leaderStyle; // solid/dotted/dash/... KoCharacterStyle::LineWeight leaderWeight; // auto/bold/thin/length/percentage/... qreal leaderWidth; // the width value if length/percentage QColor leaderColor; ///< if color is valid, then use this instead of the (current) text color QString leaderText; ///< character to print as the leader (filler of the tabbed space) bool operator==(const Tab &tab) const; }; /** * Text resources per calligra-document. * \sa KoDocumentResourceManager KoShapeController::resourceManager() */ enum DocumentResource { ChangeTracker = KoDocumentResourceManager::KoTextStart + 1, ///< KoChangeTracker InlineTextObjectManager, ///< The KoText inline-text-object manager. KoInlineTextObjectManager TextRangeManager, ///< The KoText inline-text-object manager. KoInlineTextObjectManager StyleManager, ///< The KoStyleManager PageProvider, ///< The KoPageProvider /** The KoDocumentRdf for the document, this will be a KoDocumentRdfBase when Soprano support is not compiled in. */ DocumentRdf }; enum KoTextFrameProperty { SubFrameType = QTextFormat::UserProperty + 1 }; enum KoSubFrameType { AuxillaryFrameType = 1, NoteFrameType }; /// Text in the objects will be positioned according to the direction. enum Direction { AutoDirection, ///< Take the direction from the text. LeftRightTopBottom, ///< Text layout for most western languages RightLeftTopBottom, ///< Text layout for languages like Hebrew TopBottomRightLeft, ///< Vertical text layout. TopBottomLeftRight, ///< Vertical text layout. ? InheritDirection ///< Direction is unspecified and should come from the container }; /// convert the string version of directions (as specified in XSL and ODF) to the Direction enum KRITATEXT_EXPORT Direction directionFromString(const QString &direction); /// convert the Direction enum to the string version of directions (as specified in XSL and ODF) KRITATEXT_EXPORT QString directionToString(Direction direction); /// There are several possible text breaks enum KoTextBreakProperty { NoBreak = 0, ///< No text break ColumnBreak, ///< Column break PageBreak ///< Page break }; /// convert the string version of text break (as specified in ODF) to the KoTextBreakProperty enum KRITATEXT_EXPORT KoTextBreakProperty textBreakFromString(const QString &textBreak); /// convert the KoTextBreakProperty enum to the string version of text break (as specified in ODF) KRITATEXT_EXPORT QString textBreakToString (KoTextBreakProperty textBreak); -///@TODO: move to KoUnit ? +///TODO: move to KoUnit ? KRITATEXT_EXPORT QTextLength parseLength (const QString &length); } Q_DECLARE_METATYPE(KoText::Tab) #endif diff --git a/plugins/flake/textshape/kotext/KoTextDebug.h b/plugins/flake/textshape/kotext/KoTextDebug.h index 063bc39056..5be3e0f03a 100644 --- a/plugins/flake/textshape/kotext/KoTextDebug.h +++ b/plugins/flake/textshape/kotext/KoTextDebug.h @@ -1,293 +1,293 @@ /* This file is part of the KDE project * Copyright (C) 2008 Girish Ramakrishnan * Copyright (C) 2009 Elvis Stansvik * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOTEXTDEBUG_H #define KOTEXTDEBUG_H #include "kritatext_export.h" class QTextDocument; class QTextFrame; class QTextBlock; class QTextTable; class QTextTableCell; class QTextFragment; class QTextCharFormat; class QTextListFormat; class QTextTableFormat; class QTextTableCellFormat; class QTextFrameFormat; class QTextBlockFormat; class QTextStream; class KoParagraphStyle; class KoCharacterStyle; class KoTableStyle; class KoTableCellStyle; #include #include /** * @brief KoText debugging class. * * This class provides a set of public static functions for debugging the structure of * QTextDocument text documents. The functions will dump the structure of the document * along with any formats in a human-friendly pseudo-XML format. * * To most top level function is dumpDocument(), which can be used to dump an entire * document. In addition to that, there's a set of functions for dumping certain * parts of a document , such as dumpFrame(), dumpBlock() et.c. * * For example, the following code * * @code * QTextDocument doc; * QTextCursor cursor(&doc); * cursor.insertText("Hello!\n"); * cursor.insertHtml("World!"); * * QTextStream out(stdout); * KoTextDebug::dumpDocument(&doc, out); * @endcode * * will result in this output: * - *
      + * @verbatim
        * 
        *   
        *     
        *       
        *         |Hello!|
        *       
        *     
        *
        *     
        *       
        *         |World!|
        *       
        *     
        *   
        * 
      - * 
      + * @endverbatim * * @sa dumpDocument(), dumpFrame(), dumpBlock() */ class KRITATEXT_EXPORT KoTextDebug { public: /** * Dump the structure of the specified document. * * @param document a pointer to the document that should be dumped. * @param out output stream to dump to. */ static void dumpDocument(const QTextDocument *document, QTextStream &out); /** * Dump the structure of the specified frame. * * @sa frameAttributes() * * @param frame a pointer to the frame that should be dumped. * @param out output stream to dump to. */ static void dumpFrame(const QTextFrame *frame, QTextStream &out); /** * Dump the structure of the specified block. * * @param block the block that should be dumped. * @param out output stream to dump to. */ static void dumpBlock(const QTextBlock &block, QTextStream &out); /** * Dump the structure of the specified table. * * @sa tableAttributes() * - * @param a pointer to the table that should be dumped. + * @param table pointer to the table that should be dumped. * @param out output stream to dump to. */ static void dumpTable(const QTextTable *table, QTextStream &out); /** * Dump the structure of the specified table cell. * * @sa tableCellAttributes() * * @param cell the cell that should be dumped. * @param out output stream to dump to. */ static void dumpTableCell(const QTextTableCell &cell, QTextStream &out); /** * Dump the contents of the specified text fragment. * * @note { The fragment content will be enclosed in '|' characters. } * * @param fragment the fragment which content should be dumped. * @param out output stream to dump to. */ static void dumpFragment(const QTextFragment &fragment, QTextStream &out); /** * Get the properties of the given text character format. * * The returned string will be formatted in XML-like attribute list format: * *
      "key=value key2=value2 ..."
      * * @param format the text character format from which properties should be fetched. * @return the formatted attribute string. */ static QString textAttributes(const QTextCharFormat &format); /** * Get the properties of the given character style. * * The returned string will be formatted in XML-like attribute list format: * *
      "key=value key2=value2 ..."
      * * @param style the character style from which properties should be fetched. * @return the formatted attribute string. */ static QString textAttributes(const KoCharacterStyle &style); /** * Get the properties of the given text block format. * * The returned string will be formatted in XML-like attribute list format: * *
      "key=value key2=value2 ..."
      * * @param format the text block format from which properties should be fetched. * @return the formatted attribute string. */ static QString paraAttributes(const QTextBlockFormat &format); /** * Get the properties of the given paragraph style. * * The returned string will be formatted in XML-like attribute list format: * *
      "key=value key2=value2 ..."
      * * @param style the paragraph style from which properties should be fetched. * @return the formatted attribute string. */ static QString paraAttributes(const KoParagraphStyle &style); /** * Get the properties of the given list format. * * The returned string will be formatted in XML-like attribute list format: * *
      "key=value key2=value2 ..."
      * * @param format the list format from which properties should be fetched. * @return the formatted attribute string. */ static QString listAttributes(const QTextListFormat &format); /** * Get the properties of the given table style. * * The returned string will be formatted in XML-like attribute list format: * *
      "key=value key2=value2 ..."
      * * @param tableStyle the table style from which properties should be fetched. * @return the formatted attribute string. */ static QString tableAttributes(const KoTableStyle &tableStyle); /** * Get the properties of the given table format. * * The returned string will be formatted in XML-like attribute list format: * *
      "key=value key2=value2 ..."
      * * @param tableFormat the table format from which properties should be fetched. * @return the formatted attribute string. */ static QString tableAttributes(const QTextTableFormat &tableFormat); /** * Get the properties of the given table cell style. * * The returned string will be formatted in XML-like attribute list format: * *
      "key=value key2=value2 ..."
      * - * @param tableStyle the table cell style from which properties should be fetched. + * @param tableCellStyle the table cell style from which properties should be fetched. * @return the formatted attribute string. */ static QString tableCellAttributes(const KoTableCellStyle &tableCellStyle); /** * Get the properties of the given table cell format. * * The returned string will be formatted in XML-like attribute list format: * *
      "key=value key2=value2 ..."
      * * @param tableCellFormat the table cell format from which properties should be fetched. * @return the formatted attribute string. */ static QString tableCellAttributes(const QTextTableCellFormat &tableCellFormat); /** * Get the properties of the given text frame format. * * The returned string will be formatted in XML-like attribute list format: * *
      "key=value key2=value2 ..."
      * - * @param format the text frame format from which properties should be fetched. + * @param frameFormat the text frame format from which properties should be fetched. * @return the formatted attribute string. */ static QString frameAttributes(const QTextFrameFormat &frameFormat); /** * Get the inline object properties of the object with the given text character format. * * The returned string will be formatted in XML-like attribute list format: * *
      "key=value key2=value2 ..."
      * - * @param format the character format of the object from which properties should be fetched. + * @param textFormat the character format of the object from which properties should be fetched. * @return the formatted attribute string. */ static QString inlineObjectAttributes(const QTextCharFormat &textFormat); private: KoTextDebug(); KoTextDebug(const KoTextDebug&); KoTextDebug operator=(const KoTextDebug&); static const QTextDocument *document; /**< Pointer to the debugged document. */ static int depth; /**< Current indentation depth. */ static const int INDENT; /**< Indentation value. */ }; #endif /* KOTEXTDEBUG_H */ diff --git a/plugins/flake/textshape/kotext/KoTextEditor.h b/plugins/flake/textshape/kotext/KoTextEditor.h index 33a4de7453..4708c735a6 100644 --- a/plugins/flake/textshape/kotext/KoTextEditor.h +++ b/plugins/flake/textshape/kotext/KoTextEditor.h @@ -1,561 +1,568 @@ /* This file is part of the KDE project * Copyright (C) 2009 Pierre Stirnweiss * Copyright (C) 2009 Thomas Zander * Copyright (C) 2011 Boudewijn Rempt * Copyright (C) 2011-2012 C. Boemann * Copyright (C) 2014 Denis Kuplyakov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOTEXTEDITOR_H #define KOTEXTEDITOR_H #include "kritatext_export.h" #include #include #include #include #include #include #include class KoListLevelProperties; class KoCharacterStyle; class KoInlineObject; class KoParagraphStyle; class KoInlineNote; class KoInlineCite; class KoBibliographyInfo; class KoCanvasBase; class KoTableOfContentsGeneratorInfo; class KoShapeAnchor; class KoShape; class KoBookmark; class KoAnnotation; class KoTextRangeManager; class KoTextVisitor; class KUndo2Command; class QTextBlock; class QTextCharFormat; class QTextBlockFormat; class QTextDocument; class QTextDocumentFragment; class QString; class QMimeData; /** * KoTextEditor is a wrapper around QTextCursor. It handles undo/redo and change * tracking for all editing commands. */ class KRITATEXT_EXPORT KoTextEditor: public QObject { Q_OBJECT public: enum ChangeListFlag { NoFlags = 0, ModifyExistingList = 1, MergeWithAdjacentList = 2, MergeExactly = 4, CreateNumberedParagraph = 8, AutoListStyle = 16, DontUnsetIfSame = 32 /// do not unset the current list style if it is already been set the same }; Q_DECLARE_FLAGS(ChangeListFlags, ChangeListFlag) explicit KoTextEditor(QTextDocument *document); ~KoTextEditor() override; /** * Retrieves the texteditor for the document of the first text shape in the current * set of selected shapes on the given canvas. * * @param canvas the canvas we will check for a suitable selected shape. * @returns a texteditor, or 0 if there is no shape active that has a QTextDocument as * userdata */ static KoTextEditor *getTextEditorFromCanvas(KoCanvasBase *canvas); public: // KoToolSelection overloads /// returns true if the wrapped QTextCursor has a selection. bool hasSelection() const; /** returns true if the current cursor position is protected from editing - * @param cached use cached value if available. + * @param useCached use cached value if available. */ bool isEditProtected(bool useCached = false) const; public: bool operator!=(const QTextCursor &other) const; bool operator<(const QTextCursor &other) const; bool operator<=(const QTextCursor &other) const; bool operator==(const QTextCursor &other) const; bool operator>(const QTextCursor &other) const; bool operator>=(const QTextCursor &other) const; const QTextCursor constCursor() const; private: // for the call to KoTextLoader::loadBody, which has a QTextCursor friend class KoTextPaste; // from KoTextEditor_p.h friend class CharFormatVisitor; // our commands can have access to us friend class DeleteTableRowCommand; friend class DeleteTableColumnCommand; friend class InsertTableRowCommand; friend class InsertTableColumnCommand; friend class ChangeTrackedDeleteCommand; friend class DeleteCommand; friend class InsertInlineObjectCommand; friend class InsertNoteCommand; friend class ParagraphFormattingCommand; friend class RenameSectionCommand; friend class NewSectionCommand; friend class SplitSectionsCommand; // for unittests friend class TestKoInlineTextObjectManager; // temporary... friend class TextShape; friend class TextTool; /** * This should be used only as read-only cursor or within a KUndo2Command sub-class which * will be added to the textEditor with addCommand. For examples of proper implementation of * such undoCommands, see the TextShape commands. */ QTextCursor* cursor(); public Q_SLOTS: - /// This adds the \ref command to the calligra undo stack. + /// This adds the \p command to the calligra undo stack. /// /// From this point forward all text manipulation is placed in the qt text systems internal - /// undostack while also adding representative subcommands to \ref command. + /// undostack while also adding representative subcommands to \p command. /// - /// The \ref command is not redone as part of this process. + /// The \p command is not redone as part of this process. /// - /// Note: Be aware that many KoTextEditor methods start their own commands thus terminating - /// the recording of this \ref command. Only use QTextCursor manipulation (with all the issues + /// \note Be aware that many KoTextEditor methods start their own commands thus terminating + /// the recording of this \p command. Only use QTextCursor manipulation (with all the issues /// that brings) or only use KoTextEditor methods that don't start their own command. /// /// The recording is automatically terminated when another command is added, which as mentioned /// can happen by executing some of the KoTextEditor methods. void addCommand(KUndo2Command *command); /// This instantly "redo" the command thus placing all the text manipulation the "redo" does /// (should be implemented with a "first redo" pattern) in the qt text systems internal - /// undostack while also adding representative subcommands to \ref command. + /// undostack while also adding representative subcommands to \p command. /// - /// When \ref command is done "redoing" no further text manipulation is added as subcommands. + /// When \p command is done "redoing" no further text manipulation is added as subcommands. /// - /// \ref command is not put on the calligra undo stack. That is the responsibility of the - /// caller, or the caller can choose to quickly undo and then delete the \ref command. + /// \p command is not put on the calligra undo stack. That is the responsibility of the + /// caller, or the caller can choose to quickly undo and then delete the \p command. void instantlyExecuteCommand(KUndo2Command *command); void registerTrackedChange(QTextCursor &selection, KoGenChange::Type changeType, const KUndo2MagicString &title, QTextFormat &format, QTextFormat &prevFormat, bool applyToWholeBlock = false); void bold(bool bold); void italic(bool italic); void underline(bool underline); void strikeOut(bool strikeOut); void setHorizontalTextAlignment(Qt::Alignment align); void setVerticalTextAlignment(Qt::Alignment align); void increaseIndent(); void decreaseIndent(); void increaseFontSize(); void decreaseFontSize(); void setFontFamily(const QString &font); void setFontSize(qreal size); void setTextColor(const QColor &color); void setTextBackgroundColor(const QColor &color); void setStyle(KoParagraphStyle *style); void setStyle(KoCharacterStyle *style); void mergeAutoStyle(const QTextCharFormat &deltaCharFormat); void applyDirectFormatting(const QTextCharFormat &deltaCharFormat, const QTextBlockFormat &deltaBlockFormat, const KoListLevelProperties &llp); /** * Insert an inlineObject (such as a variable) at the current cursor position. Possibly replacing the selection. * @param inliner the object to insert. - * @param cmd a parent command for the commands created by this methods. If present, the commands + * @param parent a parent command for the commands created by this methods. If present, the commands * will not be added to the document's undo stack automatically. */ void insertInlineObject(KoInlineObject *inliner, KUndo2Command *parent = 0); /** * update the position of all inline objects from the given start point to the given end point. * @param start start position for updating. If 0, we update from the start of the document * @param end end position for updating. If -1, we update to the end of the document */ void updateInlineObjectPosition(int start = 0, int end = -1); /** * Remove the KoShapeAnchor objects from the document. * * NOTE: Call this method only when the shapes belonging to the anchors have been deleted. */ void removeAnchors(const QList &anchors, KUndo2Command *parent); /** * Remove the KoAnnotation objects from the document. * * NOTE: Call this method only when the shapes belonging to the annotations have been deleted. * This is not the way to delete annotations directly - instead delete the shape or * delete the text containing the annotation */ void removeAnnotations(const QList &annotations, KUndo2Command *parent); /** * At the current cursor position, insert a marker that marks the next word as being part of the index. * @returns returns the index marker when successful, or 0 if failed. Failure can be because there is no word * at the cursor position or there already is an index marker available. */ KoInlineObject *insertIndexMarker(); /// add a bookmark on current cursor location or current selection KoBookmark *addBookmark(const QString &name); /// Add an annotation at the current cursor location or the current selection. KoAnnotation *addAnnotation(KoShape *annotationShape); KoTextRangeManager *textRangeManager() const; /** * Insert a frame break at the cursor position, moving the rest of the text to the next frame. */ void insertFrameBreak(); /** * paste the given mimedata object at the current position * @param canvas the canvas we used when placing the shape. * @param mimeData: the mimedata containing text, html or odf * @param pasteAsText: if true, paste without formatting */ void paste(KoCanvasBase *canvas, const QMimeData *mimeData, bool pasteAsText=false); /** * @param numberingEnabled when true, we will enable numbering for the current paragraph (block). */ void toggleListNumbering(bool numberingEnabled); /** * change the current block's list properties */ void setListProperties(const KoListLevelProperties &llp, ChangeListFlags flags = ChangeListFlags(ModifyExistingList | MergeWithAdjacentList), KUndo2Command *parent = 0); // ------------------------------------------------------------- // Wrapped QTextCursor methods // ------------------------------------------------------------- int anchor() const; bool atBlockEnd() const; bool atBlockStart() const; bool atEnd() const; bool atStart() const; QTextBlock block() const; QTextCharFormat blockCharFormat() const; QTextBlockFormat blockFormat() const; int blockNumber() const; QTextCharFormat charFormat() const; void clearSelection(); int columnNumber() const; void deleteChar(); void deletePreviousChar(); QTextDocument *document() const; /// Same as Qt, only to be used inside KUndo2Commands KUndo2Command *beginEditBlock(const KUndo2MagicString &title = KUndo2MagicString()); void endEditBlock(); /** * Delete one character in the specified direction or a selection. * Warning: From the outside this method should only be used with a parent command * and only if there is a selection * @param previous should be true if act like backspace + * @param parent the parent command used for stacking */ void deleteChar(bool previous, KUndo2Command *parent = 0); bool hasComplexSelection() const; /** * Insert a table at the current cursor position. * @param rows the number of rows in the created table. * @param columns the number of columns in the created table. */ void insertTable(int rows, int columns); /** * Insert a table row above the current cursor position (if in a table). */ void insertTableRowAbove(); /** * Insert a table row below the current cursor position (if in a table). */ void insertTableRowBelow(); /** * Insert a table column to the left of the current cursor position (if in a table). */ void insertTableColumnLeft(); /** * Insert a table column to the right of the current cursor position (if in a table). */ void insertTableColumnRight(); /** * Delete a table column where the cursor is (if in a table). */ void deleteTableColumn(); /** * Delete a table row where the cursor is (if in a table). */ void deleteTableRow(); /** * Merge table cells (selected by the cursor). */ void mergeTableCells(); /** * Split table cells (selected by the cursor) that were previously merged. */ void splitTableCells(); /** * Sets the width of a table column. * @param table is the table to be adjusted. * @param column the column that is to be adjusted. + * @param width the new width of the column. + * @param parentCommand the parent command used for stacking. */ void adjustTableColumnWidth(QTextTable *table, int column, qreal width, KUndo2Command *parentCommand = 0); /** * Sets the height of a table row. * @param table is the table to be adjusted. * @param row the row that is to be adjusted. + * @param height the row height. + * @param parentCommand the parent command used for stacking. */ void adjustTableRowHeight(QTextTable *table, int row, qreal height, KUndo2Command *parentCommand = 0); /** * Changes the width of a table by adjusting the margins. * @param table is the table to be adjusted. * @param dLeft delta value for the left margin. * @param dRight delta value for the right margin. */ void adjustTableWidth(QTextTable *table, qreal dLeft, qreal dRight); /** * Sets the border formatting of a side in a table cell. * @param table is the table to be adjusted. - * @param column the column coordinate of the cell that is to be adjusted. * @param row the row coordinate of the cell that is to be adjusted. + * @param column the column coordinate of the cell that is to be adjusted. + * @param cellSide the side border of the cell. + * @param data the border data. */ void setTableBorderData(QTextTable *table, int row, int column, KoBorder::BorderSide cellSide, const KoBorder::BorderData &data); /** * Insert a footnote at the current cursor position * @return a pointer to the inserted footnote */ KoInlineNote *insertFootNote(); /** * Insert an endnote at the current cursor position * @return a pointer to the inserted endnote */ KoInlineNote *insertEndNote(); /** * Insert a table of Contents at the current cursor position. */ void insertTableOfContents(KoTableOfContentsGeneratorInfo *info); /** * Configures various values of a ToC to the one passed in info */ void setTableOfContentsConfig(KoTableOfContentsGeneratorInfo *info, const QTextBlock &block); void insertBibliography(KoBibliographyInfo *info); KoInlineCite *insertCitation(); /** * Inserts the supplied text at the current cursor position. If the second argument is * supplied, a link is inserted at the current cursor position with the hRef as given * by the user. To test whether the supplied link destination is a web url or a bookmark, * a regular expression ( \\S+://\\S+ ) is used. * @param text is the text to be inserted * @param hRef if supplied is the Hypertext reference */ void insertText(const QString &text, const QString &hRef = QString()); void insertHtml(const QString &html); void mergeBlockFormat( const QTextBlockFormat &modifier); bool movePosition(QTextCursor::MoveOperation operation, QTextCursor::MoveMode mode = QTextCursor::MoveAnchor, int n = 1); /** * Inserts a new paragraph and warps it to new section * Source: * some|textP * Result: * someP * [|textP] * * [] -- section bounds * | -- cursor зщышешщт * P -- paragraph sign */ void newSection(); /** * Splits sections startings and inserts paragraph between them. * Source: {sectionIdToInsertBefore == 1} * [[[sometext... * ^ * 012 * Result: * [P * [[sometext... * * [] -- section bounds * P -- paragraph sign */ void splitSectionsStartings(int sectionIdToInsertBefore); /** * Splits section endings and insert paragraph between them. * Source: {sectionIdToInsertAfter == 1} * sometext]]] * ^ * 012 * Result: * sometext]]P * P] * * [] -- section bounds * P -- paragraph sign */ void splitSectionsEndings(int sectionIdToInsertAfter); void renameSection(KoSection *section, const QString &newName); void newLine(); bool isWithinSelection(int position) const; int position() const; void select(QTextCursor::SelectionType selection); QString selectedText() const; QTextDocumentFragment selection() const; int selectionEnd() const; int selectionStart() const; void setBlockFormat(const QTextBlockFormat &format); void setCharFormat(const QTextCharFormat &format); void setPosition(int pos, QTextCursor::MoveMode mode = QTextCursor::MoveAnchor); void setVisualNavigation(bool on); bool visualNavigation() const; const QTextFrame *currentFrame () const; const QTextList *currentList () const; const QTextTable *currentTable () const; Q_SIGNALS: void cursorPositionChanged(); void textFormatChanged(); void characterStyleApplied(KoCharacterStyle *style); void paragraphStyleApplied(KoParagraphStyle *style); protected: void recursivelyVisitSelection(QTextFrame::iterator it, KoTextVisitor &visitor) const; private: Q_PRIVATE_SLOT(d, void documentCommandAdded()) class Private; friend class Private; Private* const d; }; Q_DECLARE_METATYPE(KoTextEditor*) Q_DECLARE_METATYPE(bool *) Q_DECLARE_OPERATORS_FOR_FLAGS(KoTextEditor::ChangeListFlags) #endif // KOTEXTEDITOR_H diff --git a/plugins/flake/textshape/kotext/KoTextEditor_p.h b/plugins/flake/textshape/kotext/KoTextEditor_p.h index d57122b9d2..18c3a53c1c 100644 --- a/plugins/flake/textshape/kotext/KoTextEditor_p.h +++ b/plugins/flake/textshape/kotext/KoTextEditor_p.h @@ -1,264 +1,264 @@ /* This file is part of the KDE project * Copyright (C) 2009 Pierre Stirnweiss * Copyright (C) 2009 Thomas Zander * Copyright (C) 2015 Soma Schliszka * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOTEXTEDITOR_P_H #define KOTEXTEDITOR_P_H #include "KoTextEditor.h" #include "KoTextDocument.h" #include "styles/KoParagraphStyle.h" #include "styles/KoStyleManager.h" #include "changetracker/KoChangeTracker.h" #include #include #include #include #include #include #include class KUndo2Command; class Q_DECL_HIDDEN KoTextEditor::Private { public: enum State { NoOp, KeyPress, Delete, Format, Custom }; explicit Private(KoTextEditor *qq, QTextDocument *document); ~Private() {} void documentCommandAdded(); void updateState(State newState, const KUndo2MagicString &title = KUndo2MagicString()); void newLine(KUndo2Command *parent); void clearCharFormatProperty(int propertyId); void emitTextFormatChanged(); KoTextEditor *q; QTextCursor caret; QTextDocument *document; QStack commandStack; bool addNewCommand; bool dummyMacroAdded; int customCommandCount; KUndo2MagicString commandTitle; State editorState; bool editProtected; bool editProtectionCached; }; class KoTextVisitor { public: /// The ObjectVisitingMode enum marks how was the visited object selected. enum ObjectVisitingMode { Partly, /// The visited object (table, cell, ...) is just @b partly selected. (Eg. just one cell is selected in the visited table) Entirely, /// The visited object (table, cell, ...) is @b entirely selected. }; explicit KoTextVisitor(KoTextEditor *editor) : m_abortVisiting(false) , m_editor(editor) { } virtual ~KoTextVisitor() {} // called whenever a visit was prevented by editprotection virtual void nonVisit() {} virtual void visitFragmentSelection(QTextCursor &) { } /** * This method allows to perform custom operation when the visitor reaches a QTextTable * @param visitedTable pointer to the currently visited table object * @param visitingMode flag, marks if the table is just partly visited or entirely */ virtual void visitTable(QTextTable *visitedTable, ObjectVisitingMode visitingMode) { Q_UNUSED(visitedTable); Q_UNUSED(visitingMode); } /** * This method allows to perform custom operation when the visitor reaches a QTextTableCell - * @param visitedTable pointer to the currently visited cell object + * @param visitedCell pointer to the currently visited cell object * @param visitingMode flag, marks if the cell is just partly visited or entirely */ virtual void visitTableCell(QTextTableCell *visitedCell, ObjectVisitingMode visitingMode) { Q_UNUSED(visitedCell); Q_UNUSED(visitingMode); } // The default implementation calls visitFragmentSelection on each fragment.intersect.selection virtual void visitBlock(QTextBlock &block, const QTextCursor &caret) { for (QTextBlock::iterator it = block.begin(); it != block.end(); ++it) { QTextCursor fragmentSelection(caret); fragmentSelection.setPosition(qMax(caret.selectionStart(), it.fragment().position())); fragmentSelection.setPosition(qMin(caret.selectionEnd(), it.fragment().position() + it.fragment().length()), QTextCursor::KeepAnchor); if (fragmentSelection.anchor() >= fragmentSelection.position()) { continue; } visitFragmentSelection(fragmentSelection); } } bool abortVisiting() { return m_abortVisiting;} void setAbortVisiting(bool abort) {m_abortVisiting = abort;} KoTextEditor * editor() const {return m_editor;} private: bool m_abortVisiting; KoTextEditor *m_editor; }; class BlockFormatVisitor { public: BlockFormatVisitor() {} virtual ~BlockFormatVisitor() {} virtual void visit(QTextBlock &block) const = 0; static void visitSelection(KoTextEditor *editor, const BlockFormatVisitor &visitor, const KUndo2MagicString &title = kundo2_i18n("Format"), bool resetProperties = false, bool registerChange = true) { int start = qMin(editor->position(), editor->anchor()); int end = qMax(editor->position(), editor->anchor()); QTextBlock block = editor->block(); if (block.position() > start) block = block.document()->findBlock(start); // now loop over all blocks that the selection contains and alter the text fragments where applicable. while (block.isValid() && block.position() <= end) { QTextBlockFormat prevFormat = block.blockFormat(); if (resetProperties) { if (KoTextDocument(editor->document()).styleManager()) { KoParagraphStyle *old = KoTextDocument(editor->document()).styleManager()->paragraphStyle(block.blockFormat().intProperty(KoParagraphStyle::StyleId)); if (old) old->unapplyStyle(block); } } visitor.visit(block); QTextCursor cursor(block); QTextBlockFormat format = cursor.blockFormat(); if (registerChange) editor->registerTrackedChange(cursor, KoGenChange::FormatChange, title, format, prevFormat, true); block = block.next(); } } }; class CharFormatVisitor { public: CharFormatVisitor() {} virtual ~CharFormatVisitor() {} virtual void visit(QTextCharFormat &format) const = 0; static void visitSelection(KoTextEditor *editor, const CharFormatVisitor &visitor, const KUndo2MagicString &title = kundo2_i18n("Format"), bool registerChange = true) { int start = qMin(editor->position(), editor->anchor()); int end = qMax(editor->position(), editor->anchor()); if (start == end) { // just set a new one. QTextCharFormat format = editor->charFormat(); visitor.visit(format); if (registerChange && KoTextDocument(editor->document()).changeTracker() && KoTextDocument(editor->document()).changeTracker()->recordChanges()) { QTextCharFormat prevFormat(editor->charFormat()); int changeId = KoTextDocument(editor->document()).changeTracker()->getFormatChangeId(title, format, prevFormat, editor->charFormat().property( KoCharacterStyle::ChangeTrackerId ).toInt()); format.setProperty(KoCharacterStyle::ChangeTrackerId, changeId); } editor->cursor()->setCharFormat(format); return; } QTextBlock block = editor->block(); if (block.position() > start) block = block.document()->findBlock(start); QList cursors; QList formats; // now loop over all blocks that the selection contains and alter the text fragments where applicable. while (block.isValid() && block.position() < end) { QTextBlock::iterator iter = block.begin(); while (! iter.atEnd()) { QTextFragment fragment = iter.fragment(); if (fragment.position() > end) break; if (fragment.position() + fragment.length() <= start) { ++iter; continue; } QTextCursor cursor(block); cursor.setPosition(fragment.position() + 1); QTextCharFormat format = cursor.charFormat(); // this gets the format one char after the position. visitor.visit(format); if (registerChange && KoTextDocument(editor->document()).changeTracker() && KoTextDocument(editor->document()).changeTracker()->recordChanges()) { QTextCharFormat prevFormat(cursor.charFormat()); int changeId = KoTextDocument(editor->document()).changeTracker()->getFormatChangeId(title, format, prevFormat, cursor.charFormat().property( KoCharacterStyle::ChangeTrackerId ).toInt()); format.setProperty(KoCharacterStyle::ChangeTrackerId, changeId); } cursor.setPosition(qMax(start, fragment.position())); int to = qMin(end, fragment.position() + fragment.length()); cursor.setPosition(to, QTextCursor::KeepAnchor); cursors.append(cursor); formats.append(format); QTextCharFormat prevFormat(cursor.charFormat()); if (registerChange) editor->registerTrackedChange(cursor,KoGenChange::FormatChange,title, format, prevFormat, false); //this will lead to every fragment having a different change until the change merging in registerTrackedChange checks also for formatChange or not? ++iter; } block = block.next(); } QList::Iterator iter = formats.begin(); Q_FOREACH (QTextCursor cursor, cursors) { cursor.setCharFormat(*iter); ++iter; } } }; #endif //KOTEXTEDITOR_P_H diff --git a/plugins/flake/textshape/kotext/KoTextEditor_undo.cpp b/plugins/flake/textshape/kotext/KoTextEditor_undo.cpp index 11d6095347..d131318109 100644 --- a/plugins/flake/textshape/kotext/KoTextEditor_undo.cpp +++ b/plugins/flake/textshape/kotext/KoTextEditor_undo.cpp @@ -1,329 +1,329 @@ /* This file is part of the KDE project * Copyright (C) 2009-2012 Pierre Stirnweiss * Copyright (C) 2006-2010 Thomas Zander * Copyright (c) 2011 Boudewijn Rempt * Copyright (C) 2011-2012 C. Boemann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoTextEditor.h" #include "KoTextEditor_p.h" #include "KoTextDocument.h" #include #include #include #include #include "TextDebug.h" /** Calligra's undo/redo framework. - The @class KoTextEditor undo/redo framework sits between the @class QTextDocument and the application's undo/redo stack. + The @c KoTextEditor undo/redo framework sits between the @c QTextDocument and the application's undo/redo stack. - When the @class QTextDocument is changed by an editing action, it internally creates an undo/redo command. When doing so a signal (undoCommandAdded()) is emitted by the @class QTextDocument in order for applications to update their undo/redo stack accordingly. - Each @class QTextDocument used in Calligra is handled by a specific @class KoTextEditor. It is responsible for on the one hand edit the @class QTextDocument, and on the other hand to listen for the QTextDocument's signal. + When the @c QTextDocument is changed by an editing action, it internally creates an undo/redo command. When doing so a signal (undoCommandAdded()) is emitted by the @c QTextDocument in order for applications to update their undo/redo stack accordingly. + Each @c QTextDocument used in Calligra is handled by a specific @c KoTextEditor. It is responsible for on the one hand edit the @c QTextDocument, and on the other hand to listen for the QTextDocument's signal. - Calligra uses a @class KUndo2Stack as its application undo/redo stack. This stack is populated by @class KUndo2Command or sub-classes of it. + Calligra uses a @c KUndo2Stack as its application undo/redo stack. This stack is populated by @c KUndo2Command or sub-classes of it. In order to limit the number of command sub-classes, KoTextEditor provides a framework which uses a generic command. - The framework is based on a sort of state machine. The KoTextEditor can be in several different states (see @enum KoTextEditor::Private::State). + The framework is based on a sort of state machine. The KoTextEditor can be in several different states (see @ref KoTextEditor::Private::State ). These are: - NoOp: this states indicates that the KoTextEditor is not editing the QTextDocument. - KeyPress: this state indicates that the user is typing text. All text typed in succession should correspond to one undo command. To be used when entering text outside of an insertTextCommand. - Delete: this state indicates that the user is deleting characters. All deletions done in succession should correspond to one undo command. To be used for deleting outside a deleteCommand. Currently not in use, our deletion is done through a command because of inline objects. - Format: this state indicates that we are formatting text. To be used when formatting outside of a command. - Custom: this state indicates that the QTextDocument is changed through a KUndo2Command. + @c NoOp : this states indicates that the KoTextEditor is not editing the QTextDocument. + @c KeyPress : this state indicates that the user is typing text. All text typed in succession should correspond to one undo command. To be used when entering text outside of an insertTextCommand. + @c Delete : this state indicates that the user is deleting characters. All deletions done in succession should correspond to one undo command. To be used for deleting outside a deleteCommand. Currently not in use, our deletion is done through a command because of inline objects. + @c Format : this state indicates that we are formatting text. To be used when formatting outside of a command. + @c Custom : this state indicates that the QTextDocument is changed through a KUndo2Command. KoTextEditor reacts differently when receiving the QTextDocument's signal, depending on its state. In addition the framework allows to encapsulate modifications in a on-the-fly created custom command (\sa beginEditBlock() endEditBlock()). Furthermore the framework allows to push complete KUndo2Commands. See the documentation file for how to use this framework. */ /* Important members: commandStack: This stack holds the headCommands. These parent the generated UndoTextCommands. When undo or redo is called, they will in turn call UndoTextCommand::undo/redo. editorState: Holds the state of the KoTextEditor. see above commandTitle: Holds the title which is to be used when creating a headCommand. addNewCommand: bool used to tell the framework to create a new headCommand and push it on the commandStack, when receiving an undoCommandAdded signal from QTextDocument. customCommandCount: counter used to keep track of nested KUndo2Commands that are pushed on the KoTextEditor. */ // This slot is called when the KoTextEditor receives the signal undoCommandAdded() from QTextDocument. A generic UndoTextCommand is used to match the QTextDocument's internal undo command. This command calls QTextDocument::undo() or QTextDocument::redo() respectively, which triggers the undo redo actions on the document. //In order to allow nesting commands, we maintain a stack of commands. The top command will be the parent of our auto generated UndoTextCommands. //Depending on the case, we might create a command which will serve as head command. This is pushed to our commandStack and eventually to the application's stack. void KoTextEditor::Private::documentCommandAdded() { class UndoTextCommand : public KUndo2Command { public: UndoTextCommand(QTextDocument *document, KoTextEditor::Private *p, KUndo2Command *parent = 0) : KUndo2Command(kundo2_i18n("Text"), parent), m_document(document) , m_p(p) {} void undo() override { QTextDocument *doc = m_document.data(); if (doc == 0) return; doc->undo(KoTextDocument(doc).textEditor()->cursor()); m_p->emitTextFormatChanged(); } void redo() override { QTextDocument *doc = m_document.data(); if (doc == 0) return; doc->redo(KoTextDocument(doc).textEditor()->cursor()); m_p->emitTextFormatChanged(); } QWeakPointer m_document; KoTextEditor::Private *m_p; }; debugText << "received a QTextDocument undoCommand signal"; debugText << "commandStack count: " << commandStack.count(); debugText << "addCommand: " << addNewCommand; debugText << "editorState: " << editorState; if (commandStack.isEmpty()) { //We have an empty stack. We need a head command which is to be pushed onto our commandStack and on the application stack if there is one. //This command will serve as a parent for the auto-generated UndoTextCommands. debugText << "empty stack, will push a new headCommand on both commandStack and application's stack. title: " << commandTitle; commandStack.push(new KUndo2Command(commandTitle)); if (KoTextDocument(document).undoStack()) { KoTextDocument(document).undoStack()->push(commandStack.top()); } addNewCommand = false; debugText << "commandStack is now: " << commandStack.count(); } else if (addNewCommand) { //We have already a headCommand on the commandStack. However we want a new child headCommand (nested commands) on the commandStack for parenting further UndoTextCommands. This shouldn't be pushed on the application's stack because it is a child of the current commandStack's top. debugText << "we have a headCommand on the commandStack but need a new child command. we will push it only on the commandStack: " << commandTitle; commandStack.push(new KUndo2Command(commandTitle, commandStack.top())); addNewCommand = false; debugText << "commandStack count is now: " << commandStack.count(); } else if ((editorState == KeyPress || editorState == Delete) && !commandStack.isEmpty() && commandStack.top()->childCount()) { //QTextDocument emits a signal on the first key press (or delete) and "merges" the subsequent ones, until an incompatible one is done. In which case it re-emit a signal. //Here we are in KeyPress (or Delete) state. The fact that the commandStack isn't empty and its top command has children means that we just received such a signal. We therefore need to pop the previous headCommand (which were either key press or delete) and create a new one to parent the UndoTextCommands. This command also need to be pushed on the application's stack. debugText << "we are in subsequent keyPress/delete state and still received a signal. we need to create a new headCommand: " << commandTitle; debugText << "so we pop the current one and push the new one on both the commandStack and the application's stack"; commandStack.pop(); commandStack.push(new KUndo2Command(commandTitle, !commandStack.isEmpty()?commandStack.top():0)); if (KoTextDocument(document).undoStack()) { KoTextDocument(document).undoStack()->push(commandStack.top()); } debugText << "commandStack count: " << commandStack.count(); } //Now we can create our UndoTextCommand which is parented to the commandStack't top headCommand. new UndoTextCommand(document, this, commandStack.top()); debugText << "done creating the dummy UndoTextCommand"; } //This method is used to update the KoTextEditor state, which will condition how the QTextDocument::undoCommandAdded signal will get handled. void KoTextEditor::Private::updateState(KoTextEditor::Private::State newState, const KUndo2MagicString &title) { debugText << "updateState from: " << editorState << " to: " << newState << " with: " << title; debugText << "commandStack count: " << commandStack.count(); if (editorState == Custom && newState != NoOp) { //We already are in a custom state (meaning that either a KUndo2Command was pushed on us, an on-the-fly macro command was started or we are executing a complex editing from within the KoTextEditor. //In that state any update of the state different from NoOp is part of that "macro". However, updating the state means that we are now wanting to have a new command for parenting the UndoTextCommand generated after the signal //from QTextDocument. This is to ensure that undo/redo actions are done in the proper order. Setting addNewCommand will ensure that we create such a child headCommand on the commandStack. This command will not be pushed on the application's stack. debugText << "we are already in a custom state. a new state, which is not NoOp is part of the macro we are doing. we need however to create a new command on the commandStack to parent a signal induced UndoTextCommand"; addNewCommand = true; if (!title.isEmpty()) commandTitle = title; else commandTitle = kundo2_i18n("Text"); debugText << "returning now. commandStack is not modified at this stage"; return; } if (newState == NoOp && !commandStack.isEmpty()) { //Calling updateState to NoOp when the commandStack isn't empty means that the current headCommand on the commandStack is finished. Further UndoTextCommands do not belong to it. So we pop it. //If after popping the headCommand we still have some commands on the commandStack means we have not finished with the highest "macro". In that case we need to stay in the "Custom" state. //On the contrary, an empty commandStack means we have finished with the "macro". In that case, we set the editor to NoOp state. A signal from the QTextDocument should also generate a new headCommand. debugText << "we are in a macro and update the state to NoOp. this means that the command on top of the commandStack is finished. we should pop it"; debugText << "commandStack count before: " << commandStack.count(); commandStack.pop(); debugText << "commandStack count after: " << commandStack.count(); if (commandStack.isEmpty()) { debugText << "we have no more commands on the commandStack. the macro is complete. next signal induced command will need to be parented to a new headCommand. Also the editor should go to NoOp"; addNewCommand = true; editorState = NoOp; } debugText << "returning now. commandStack count: " << commandStack.count(); return; } if (editorState != newState || commandTitle != title) { //We are not in "Custom" state but either are moving to a new state (from editing to format,...) or the command type is the same, but not the command itself (like format:bold, format:italic). The later case is caracterised by a different command title. //When we change command, we need to pop the current commandStack's top and ask for a new headCommand to be created. debugText << "we are not in a custom state but change the command"; debugText << "commandStack count: " << commandStack.count(); if (!commandStack.isEmpty()) { debugText << "the commandStack is not empty. however the command on it is not a macro. so we pop it and ask to recreate a new one: " << title; commandStack.pop(); addNewCommand = true; } } editorState = newState; if (!title.isEmpty()) commandTitle = title; else commandTitle = kundo2_i18n("Text"); debugText << "returning now. commandStack count: " << commandStack.count(); } /// This method is used to push a complete KUndo2Command on the KoTextEditor. This command will be pushed on the application's stack if needed. The logic allows to push several commands which are then going to be nested, provided these children are pushed from within the redo method of their parent. void KoTextEditor::addCommand(KUndo2Command *command) { debugText << "we receive a command to add on the stack."; debugText << "commandStack count: " << d->commandStack.count(); debugText << "customCommandCount counter: " << d->customCommandCount << " will increase"; //We increase the customCommandCount counter to inform the framework that we are having a further KUndo2Command and update the KoTextEditor's state to Custom. //However, this update will request a new headCommand to be pushed on the commandStack. This is what we want for internal complex editions but not in this case. Indeed, it must be the KUndo2Command which will parent the UndoTextCommands. Therefore we set the addNewCommand back to false. //If the commandStack is empty, we are the highest "macro" command and we should therefore push the KUndo2Command on the application's stack. //On the contrary, if the commandStack is not empty, or the pushed command has a parent, it means that we are adding a nested KUndo2Command. In which case we just want to put it on the commandStack to parent UndoTextCommands. We need to call the redo method manually though. ++d->customCommandCount; debugText << "we will now go to custom state"; d->updateState(KoTextEditor::Private::Custom, (!command->text().isEmpty())?command->text():kundo2_i18n("Text")); debugText << "but will set the addCommand to false. we don't want a new headCommand"; d->addNewCommand = false; debugText << "commandStack count is: " << d->commandStack.count(); if (d->commandStack.isEmpty()) { debugText << "the commandStack is empty. this means we are the top most command"; d->commandStack.push(command); debugText << "command pushed on the commandStack. count: " << d->commandStack.count(); KUndo2QStack *stack = KoTextDocument(d->document).undoStack(); if (stack && !command->hasParent()) { debugText << "we have an application stack and the command is not a sub command of a non text command (which have been pushed outside kotext"; stack->push(command); debugText << "so we pushed it on the application's' stack"; } else { debugText << "we either have no application's stack, or our command is actually the child of a non kotext command"; command->redo(); debugText << "still called redo on it"; } } else { debugText << "the commandStack is not empty, our command is actually nested in another kotext command. we don't push on the application stack but only on the commandStack"; d->commandStack.push(command); debugText << "commandStack count after push: " << d->commandStack.count(); command->redo(); debugText << "called redo still"; } //When we reach that point, the command has been executed. We first need to clean up all the automatically generated headCommand on our commandStack, which could potentially have been created during the editing. When we reach our pushed command, the commandStack is clean. We can then call a state update to NoOp and decrease the customCommandCount counter. debugText << "the command has been executed. we need to clean up the commandStack of the auto generated headCommands"; debugText << "before cleaning. commandStack count: " << d->commandStack.count(); while (d->commandStack.top() != command) { d->commandStack.pop(); } debugText << "after cleaning. commandStack count: " << d->commandStack.count() << " will set NoOp"; d->updateState(KoTextEditor::Private::NoOp); debugText << "after NoOp set. inCustomCounter: " << d->customCommandCount << " will decrease and return"; --d->customCommandCount; } /// DO NOT USE THIS. It stays here for compiling reasons. But it will severely break everything. Again: DO NOT USE THIS. void KoTextEditor::instantlyExecuteCommand(KUndo2Command *command) { d->updateState(KoTextEditor::Private::Custom, (!command->text().isEmpty())?command->text():kundo2_i18n("Text")); command->redo(); // instant replay done let's not keep it dangling if (!command->hasParent()) { d->updateState(KoTextEditor::Private::NoOp); } } /// This method is used to start an on-the-fly macro command. Use KoTextEditor::endEditBlock to stop it. /// *** /// Important note: /// *** /// The framework does not allow to push a complete KUndo2Command (through KoTextEditor::addCommand) from within an EditBlock. Doing so will lead in the best case to several undo/redo commands on the application's stack instead of one, in the worst case to an out of sync application's stack. /// *** KUndo2Command *KoTextEditor::beginEditBlock(const KUndo2MagicString &title) { debugText << "beginEditBlock"; debugText << "commandStack count: " << d->commandStack.count(); debugText << "customCommandCount counter: " << d->customCommandCount; if (!d->customCommandCount) { // We are not in a custom macro command. So we first need to update the KoTextEditor's state to Custom. Additionally, if the commandStack is empty, we need to create a master headCommand for our macro and push it on the stack. debugText << "we are not in a custom command. will update state to custom"; d->updateState(KoTextEditor::Private::Custom, title); debugText << "commandStack count: " << d->commandStack.count(); if (d->commandStack.isEmpty()) { debugText << "the commandStack is empty. we need a dummy headCommand both on the commandStack and on the application's stack"; KUndo2Command *command = new KUndo2Command(title); d->commandStack.push(command); ++d->customCommandCount; d->dummyMacroAdded = true; //This bool is used to tell endEditBlock that we have created a master headCommand. KUndo2QStack *stack = KoTextDocument(d->document).undoStack(); if (stack) { stack->push(command); } else { command->redo(); } debugText << "done adding the headCommand. commandStack count: " << d->commandStack.count() << " inCommand counter: " << d->customCommandCount; } } //QTextDocument sends the undoCommandAdded signal at the end of the QTextCursor edit block. Since we want our master headCommand to parent the signal induced UndoTextCommands, we should not call QTextCursor::beginEditBlock for the headCommand. if (!(d->dummyMacroAdded && d->customCommandCount == 1)) { debugText << "we did not add a dummy command, or we are further down nesting. call beginEditBlock on the caret to nest the QTextDoc changes"; //we don't call beginEditBlock for the first headCommand because we want the signals to be sent before we finished our command. d->caret.beginEditBlock(); } debugText << "will return top od commandStack"; return (d->commandStack.isEmpty())?0:d->commandStack.top(); } void KoTextEditor::endEditBlock() { debugText << "endEditBlock"; //Only the self created master headCommand (see beginEditBlock) is left on the commandStack, we need to decrease the customCommandCount counter that we increased on creation. //If we are not yet at this master headCommand, we can call QTextCursor::endEditBlock if (d->dummyMacroAdded && d->customCommandCount == 1) { debugText << "only the created dummy headCommand from beginEditBlock is left. we need to decrease further the nesting counter"; //we don't call caret.endEditBlock because we did not begin a block for the first headCommand --d->customCommandCount; d->dummyMacroAdded = false; } else { debugText << "we are not at our top dummy headCommand. call caret.endEditBlock"; d->caret.endEditBlock(); } if (!d->customCommandCount) { //We have now finished completely the macro, set the editor state to NoOp then. debugText << "we have finished completely the macro, set the state to NoOp now. commandStack count: " << d->commandStack.count(); d->updateState(KoTextEditor::Private::NoOp); debugText << "done setting the state. editorState: " << d->editorState << " commandStack count: " << d->commandStack.count(); } } diff --git a/plugins/flake/textshape/kotext/KoTextRdfCore.h b/plugins/flake/textshape/kotext/KoTextRdfCore.h index d2295e4650..a0aecac055 100644 --- a/plugins/flake/textshape/kotext/KoTextRdfCore.h +++ b/plugins/flake/textshape/kotext/KoTextRdfCore.h @@ -1,149 +1,151 @@ /* This file is part of the KDE project Copyright (C) 2010 KO GmbH This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KO_TEXT_RDF_CORE_H #define KO_TEXT_RDF_CORE_H #include "kritatext_export.h" #include // this file can only be used by code that is built // with soprano enabled. #include class KoStore; class KoXmlWriter; /** * @short Basic low level methods that are available to KoText objects * * Low level functionality such as streaming a Soprano::Model to and * from an ODF container is provided here so that both KoDocumentRdf * and other code in libs/kotext can share it. * * @author Ben Martin * @see KoDocumentRdf */ namespace KoTextRdfCore { /** * Save the RDF selected triples from model to the store with the * given RDF/XML filename */ bool saveRdf( QSharedPointer model, Soprano::StatementIterator triples, KoStore *store, KoXmlWriter *manifestWriter, const QString &fileName); /** * Save the given RDF model to the manifest.rdf file. The idmap is used * to maintain xml:id links from the model so they will be valid with * the content.xml that generated the idmap. */ bool createAndSaveManifest(QSharedPointer model, const QMap &idmap, KoStore *store, KoXmlWriter *manifestWriter); /** * Load the manifest.rdf file from the ODF container store * into the model provided. */ bool loadManifest(KoStore *store, QSharedPointer model); /** * For debugging, dump the model to debugText along with the * given header message for identification */ void dumpModel(const QString &message, QSharedPointer model); /** * Load an Rdf linked list of statements. See saveList() for the * details. The return value of loadList() is the equivalent of * dataBNodeList in saveList(). * * @see saveList() */ QList KRITATEXT_EXPORT loadList(QSharedPointer model, Soprano::Node ListHeadSubject); /** * Save an Rdf List of data nodes into the model. Rdf defines a * linked list format in the * http://www.w3.org/1999/02/22-rdf-syntax-ns URI namespace using * first/rest to link the current element with the "rest" of the * list. A scheme that will be familiar to many lisp programmers * car/cdr. Unfortunately dealing with such lists directly is * clumsy so this and loadList() let you store a list of data * nodes and these methods create all the boilerplate Rdf triples * to store/read a simple QList of nodes to Rdf properly. You * supply the list header node ListHeadSubject which is normally * the subject that you want the list associated with in Rdf. The * other nodes used in the internal structure of the Rdf list are * just random bnodes as shown below. If you have a previous, * existing list then this method will remove those nodes first so * that the Rdf model does not grow with disgarded list nodes over * time. * * The old list nodes are removed if they exist, and a new list is * created starting at ListHeadSubject, and linking all the nodes * in dataBNodeList using the supplied rdf context. Use the * loadList() method to get the list dataBNodeList back from the * model again. * * The result will be like: + * @verbatim * ListHeadSubject 22-rdf-syntax-ns#first dataBNodeList[0] * ListHeadSubject 22-rdf-syntax-ns#rest bnodeA * bnodeA 22-rdf-syntax-ns#first dataBNodeList[1] * bnodeA 22-rdf-syntax-ns#rest bnodeB * ... * bnodeZ 22-rdf-syntax-ns#first dataBNodeList[N] * bnodeZ 22-rdf-syntax-ns#rest nil + * @endverbatim * */ void KRITATEXT_EXPORT saveList(QSharedPointer model, Soprano::Node ListHeadSubject, QList &dataBNodeList, Soprano::Node context); /** * Using model->removeStatements() will fail if the statement does not * exist in the model. This method is a bit sloppier in that it ignores * attempts to remove statements twice, or ones that no longer exist * in the model. This is handy for set based remove/add bulk updates * because you don't have to ensure that a statement is added only once * to the remove list. */ void KRITATEXT_EXPORT removeStatementsIfTheyExist( QSharedPointer model, const QList &removeList); /** * Given the Subj+Pred get the Object for the triple. If there are * more than one object, a random one from the possible candidates is * returned. This is mainly useful when you *know* there is only zero * or one object. */ Soprano::Node KRITATEXT_EXPORT getObject(QSharedPointer model, Soprano::Node s, Soprano::Node p); QString KRITATEXT_EXPORT getProperty(QSharedPointer m, Soprano::Node subj, Soprano::Node pred, const QString &defval); QString KRITATEXT_EXPORT optionalBindingAsString(Soprano::QueryResultIterator& it, const QString &bindingName, const QString &def = QString()); QByteArray KRITATEXT_EXPORT fileToByteArray(const QString &fileName); } #endif diff --git a/plugins/flake/textshape/kotext/commands/ChangeListCommand.h b/plugins/flake/textshape/kotext/commands/ChangeListCommand.h index 2f2cfaffe8..0aacc97fc4 100644 --- a/plugins/flake/textshape/kotext/commands/ChangeListCommand.h +++ b/plugins/flake/textshape/kotext/commands/ChangeListCommand.h @@ -1,106 +1,107 @@ /* This file is part of the KDE project * Copyright (C) 2007 Thomas Zander * Copyright (C) 2008 Girish Ramakrishnan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef CHANGELISTCOMMAND #define CHANGELISTCOMMAND #include "KoTextCommandBase.h" #include "KoListStyle.h" #include "KoTextEditor.h" #include "KoListLevelProperties.h" #include #include #include class KoList; /** * This command is useful to alter the list-association of a single textBlock. */ class ChangeListCommand : public KoTextCommandBase { public: - //FIXME: following comments seems to describe another function /** - * Change the list property of 'block'. - * @param block the paragraph to change the list property of - * @param style indicates which style to use. + * Change the list command. + * @param cursor text cursor properties. + * @param levelProperties level properties. + * @param flags the list flags. * @param parent the parent undo command for macro functionality */ ChangeListCommand(const QTextCursor &cursor, const KoListLevelProperties &levelProperties, KoTextEditor::ChangeListFlags flags, KUndo2Command *parent = 0); /** - * Change the list property of 'block'. - * @param block the paragraph to change the list property of - * @param style the style to apply - * @param exact if true then the actual style 'style' should be set, if false we possibly merge with another similar style that is near the block + * Change the list command. + * @param cursor text cursor properties. + * @param style the style to apply. + * @param level the level in the list. + * @param flags the list flags. * @param parent the parent undo command for macro functionality */ ChangeListCommand(const QTextCursor &cursor, KoListStyle *style, int level, KoTextEditor::ChangeListFlags flags, KUndo2Command *parent = 0); ~ChangeListCommand() override; /// redo the command void redo() override; /// revert the actions done in redo void undo() override; /// reimplemented from KUndo2Command int id() const override { return 58450687; } /// reimplemented from KUndo2Command bool mergeWith(const KUndo2Command *other) override; private: enum CommandAction { CreateNew, ModifyExisting, ReparentList, MergeList, RemoveList }; bool extractTextBlocks(const QTextCursor &cursor, int level, KoListStyle::Style newStyle = KoListStyle::None); int detectLevel(const QTextBlock &block, int givenLevel); void initList(KoListStyle *style); bool formatsEqual(const KoListLevelProperties &llp, const QTextListFormat &format); int m_flags; bool m_first; bool m_alignmentMode; QList m_blocks; QHash m_formerProperties; QHash m_newProperties; QHash m_levels; QHash m_list; QHash m_oldList; QHash m_actions; }; #endif diff --git a/plugins/flake/textshape/kotext/opendocument/KoTextWriter.h b/plugins/flake/textshape/kotext/opendocument/KoTextWriter.h index 250e4e1c20..5a9d668df6 100644 --- a/plugins/flake/textshape/kotext/opendocument/KoTextWriter.h +++ b/plugins/flake/textshape/kotext/opendocument/KoTextWriter.h @@ -1,86 +1,87 @@ /* This file is part of the KDE project * Copyright (C) 2008 Girish Ramakrishnan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOTEXTWRITER_H #define KOTEXTWRITER_H #include "kritatext_export.h" class KoShapeSavingContext; class KoStyleManager; class QTextDocument; class QTextBlock; class QTextBlockFormat; class QTextCharFormat; class QString; class KoDocumentRdfBase; /** * KoTextWriter saves the text ODF of a shape */ class KRITATEXT_EXPORT KoTextWriter { public: /** * Constructor. * * @param context The context the KoTextWriter is called in + * @param rdfData The RDF data */ explicit KoTextWriter(KoShapeSavingContext &context, KoDocumentRdfBase *rdfData = 0); /** * Destructor. */ ~KoTextWriter(); /// XXX: APIDOX! static void saveOdf(KoShapeSavingContext &context, KoDocumentRdfBase *rdfData, QTextDocument *document, int from, int to); /** * Save a paragraph style used in a text block * * This checks if the style is a document style or a automatic style * and saves it accordingly. * * @param block The block form which the style information are taken * @param styleManager The used style manager * @param context The saving context */ static QString saveParagraphStyle(const QTextBlock &block, KoStyleManager *styleManager, KoShapeSavingContext &context); static QString saveParagraphStyle(const QTextBlockFormat &blockFormat, const QTextCharFormat &charFormat, KoStyleManager *styleManager, KoShapeSavingContext &context); /** * Writes the portion of document contained within 'from' and 'to' * * @param document The text document we are saving. There can be more than one * text document in the office document, but we don't care * @param from the start position in characters from which we save * @param to the end position in characters up to which we save. If -1, we save to the end */ void write(const QTextDocument *document, int from, int to = -1); private: class Private; Private* const d; }; #endif diff --git a/plugins/flake/textshape/kotext/styles/KoTableCellStyle.h b/plugins/flake/textshape/kotext/styles/KoTableCellStyle.h index af96603da3..f8dadfd088 100644 --- a/plugins/flake/textshape/kotext/styles/KoTableCellStyle.h +++ b/plugins/flake/textshape/kotext/styles/KoTableCellStyle.h @@ -1,376 +1,376 @@ /* This file is part of the KDE project * Copyright (C) 2006-2010 Thomas Zander * Copyright (C) 2008 Thorsten Zachmann * Copyright (C) 2008 Girish Ramakrishnan * Copyright (C) 2009 KO GmbH * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOTABLECELLSTYLE_H #define KOTABLECELLSTYLE_H #include "KoText.h" #include "kritatext_export.h" #include #include #include #include #include struct Property; class QTextTableCell; class QRectF; class KoStyleStack; class KoGenStyle; class KoParagraphStyle; class KoShapeLoadingContext; class KoShapeSavingContext; class KoTableCellStylePrivate; class QString; class QVariant; /** * A container for all properties for the table cell style. * Each tablecell in the main text either is based on a table cell style, or its not. Where * it is based on a table cell style this is indecated that it has a property 'StyleId' * with an integer as value. The integer value corresponds to the styleId() output of * a specific KoTableCellStyle. * @see KoStyleManager */ class KRITATEXT_EXPORT KoTableCellStyle : public QObject { Q_OBJECT public: enum CellProtectionFlag { NoProtection, HiddenAndProtected, Protected, FormulaHidden, ProtectedAndFormulaHidden }; enum CellTextDirection { Default = 0, LeftToRight, TopToBottom }; enum RotationAlignment { RAlignNone, RAlignBottom, RAlignTop, RAlignCenter }; enum Property { StyleId = QTextTableCellFormat::UserProperty + 7001, ShrinkToFit, ///< Shrink the cell content to fit the size Wrap, ///< Wrap the text within the cell CellProtection, ///< The cell protection when the table is protected PrintContent, ///< Should the content of this cell be printed RepeatContent, ///< Display the cell content as many times as possible DecimalPlaces, ///< Count the maximum number of decimal places to display AlignFromType, ///< Should the alignment property be respected or should the alignment be based on the value type RotationAngle, ///< Rotation angle of the cell content, in degrees Direction, ///< The direction of the text in the cell. This is a CellTextDirection. RotationAlign, ///< How the edge of the text is aligned after rotation. This is a RotationAlignment TextWritingMode, ///< KoText::Direction, the direction for writing text in the cell VerticalGlyphOrientation, ///< bool, specify whether this feature is enabled or not CellBackgroundBrush, ///< the cell background brush, as QTextFormat::BackgroundBrush is used by paragraphs VerticalAlignment, ///< the vertical alignment oinside the cell MasterPageName, ///< Optional name of the master-page InlineRdf, ///< Optional KoTextInlineRdf object Borders, ///< KoBorder, the borders of this cell Shadow, ///< KoShadowStyle, the shadow of this cell CellIsProtected ///< boolean, if true, the cell is protected against edits /// It's not really a property of KoTableCellStyle but defined here for convenience ,LastCellStyleProperty }; /// Constructor explicit KoTableCellStyle(QObject *parent = 0); /// Creates a KoTableCellStyle with the given table cell format, and \a parent explicit KoTableCellStyle(const QTextTableCellFormat &tableCellFormat, QObject *parent = 0); KoTableCellStyle(const KoTableCellStyle &other); KoTableCellStyle& operator=(const KoTableCellStyle &other); /// Destructor ~KoTableCellStyle() override; /// Creates a KoTableCellStyle that represents the formatting of \a block. static KoTableCellStyle *fromTableCell(const QTextTableCell &table, QObject *parent = 0); /// Creates a clean QTextCharFormat, but keeps all the table cell properties. /// This is needed since block.charformat doubles as the QTextTableCellFormat /// This method works even if \a charFormat is not a QTextTableCellFormat static QTextCharFormat cleanCharFormat(const QTextCharFormat &charFormat); /// creates a clone of this style with the specified parent KoTableCellStyle *clone(QObject *parent = 0); /** - * Adjust the bounding rectangle \boundingRect according to the paddings and margins + * Adjust the bounding rectangle \p boundingRect according to the paddings and margins * of this border data. The inverse of this function is boundingRect(). * * \sa boundingRect() * - * @param the bounding rectangle. + * @param boundingRect the bounding rectangle. * @return the adjusted rectangle. */ QRectF contentRect(const QRectF &boundingRect) const; /** * Get the bounding rect given a content rect, this is the inverse of contentRect(). * * \sa contentRect() * * @param contentRect the content rectangle. * @return the bounding rectangle. */ QRectF boundingRect(const QRectF &contentRect) const; void setBackground(const QBrush &brush); /// See similar named method on QTextBlockFormat QBrush background() const; /// See similar named method on QTextBlockFormat void clearBackground(); /** * Get the paragraph style for this cell style * * @return the paragraph style */ KoParagraphStyle *paragraphStyle() const; bool shrinkToFit() const; void setShrinkToFit(bool state); bool repeatContent() const; void setRepeatContent(bool state); void setLeftPadding(qreal padding); void setTopPadding(qreal padding); void setRightPadding(qreal padding); void setBottomPadding(qreal padding); void setPadding(qreal padding); qreal leftPadding() const; qreal rightPadding() const; qreal topPadding() const; qreal bottomPadding() const; void setAlignment(Qt::Alignment alignment); Qt::Alignment alignment() const; KoText::Direction textDirection() const; void setTextDirection (KoText::Direction value); void setWrap(bool state); bool wrap() const; CellProtectionFlag cellProtection() const; void setCellProtection (CellProtectionFlag protection); void setPrintContent(bool state); bool printContent() const; void setDecimalPlaces(int places); int decimalPlaces() const; void setAlignFromType(bool state); bool alignFromType() const; void setRotationAngle(qreal value); qreal rotationAngle() const; void setDirection(CellTextDirection direction); CellTextDirection direction() const; void setRotationAlignment(RotationAlignment align); RotationAlignment rotationAlignment () const; void setVerticalGlyphOrientation(bool state); bool verticalGlyphOrientation() const; void setBorders(const KoBorder &borders); KoBorder borders() const; void setShadow (const KoShadowStyle &shadow); KoShadowStyle shadow() const; /// set the parent style this one inherits its unset properties from. void setParentStyle(KoTableCellStyle *parent); /// return the parent style KoTableCellStyle *parentStyle() const; /// return the name of the style. QString name() const; /// set a user-visible name on the style. void setName(const QString &name); /// each style has a unique ID (non persistent) given out by the styleManager int styleId() const; /// each style has a unique ID (non persistent) given out by the styleManager void setStyleId(int id); /// return the optional name of the master-page or a QString() if this paragraph isn't attached to a master-page. QString masterPageName() const; /// Set the name of the master-page. void setMasterPageName(const QString &name); /// copy all the properties from the other style to this style, effectively duplicating it. void copyProperties(const KoTableCellStyle *style); /** * Apply this style to a textTableCellFormat by copying all properties from this, and parent * styles to the target textTableCellFormat. Note that the paragraph format will not be applied * using this method, use the other method for that. * No default values are applied. */ void applyStyle(QTextTableCellFormat &format) const; void applyStyle(QTextTableCell &cell) const; void remove(int key); /// Compare the paragraph, character and list properties of this style with the other bool operator==(const KoTableCellStyle &other) const; void removeDuplicates(const KoTableCellStyle &other); /** * Load the style form the element * * @param context the odf loading context * @param element the element containing the */ void loadOdf(const KoXmlElement *element, KoShapeLoadingContext &context); void saveOdf(KoGenStyle &style, KoShapeSavingContext &context); /** * Returns true if this paragraph style has the property set. * Note that this method does not delegate to the parent style. * @param key the key as found in the Property enum */ bool hasProperty(int key) const; /** * Set a property with key to a certain value, overriding the value from the parent style. * If the value set is equal to the value of the parent style, the key will be removed instead. * @param key the Property to set. * @param value the new value to set on this style. * @see hasProperty(), value() */ void setProperty(int key, const QVariant &value); /** * Return the value of key as represented on this style, taking into account parent styles. * You should consider using the direct accessors for individual properties instead. * @param key the Property to request. * @returns a QVariant which holds the property value. */ QVariant value(int key) const; /** * Set the properties of an edge. * * @param side defines which edge this is for. * @param style the border style for this side. * @param totalWidth the thickness of the border. Sum of outerwidth, spacing and innerwidth for double borders * @param color the color of the border line(s). */ void setEdge(KoBorder::BorderSide side, KoBorder::BorderStyle style, qreal totalWidth, const QColor &color); /** * Set the properties of a double border. * Note: you need to set the edge first or that would overwrite these values. * * The values will not be set if the border doesn't have a double style * * @param side defines which edge this is for. * @param space the amount of spacing between the outer border and the inner border in case of style being double * @param innerWidth the thickness of the inner border line in case of style being double */ void setEdgeDoubleBorderValues(KoBorder::BorderSide side, qreal innerWidth, qreal space); /** * Check if the border data has any borders. * * @return true if there has been at least one border set. */ bool hasBorders() const; qreal leftBorderWidth() const; qreal rightBorderWidth() const; qreal topBorderWidth() const; qreal bottomBorderWidth() const; qreal leftInnerBorderWidth() const; qreal rightInnerBorderWidth() const; qreal topInnerBorderWidth() const; qreal bottomInnerBorderWidth() const; qreal leftOuterBorderWidth() const; qreal rightOuterBorderWidth() const; qreal topOuterBorderWidth() const; qreal bottomOuterBorderWidth() const; KoBorder::BorderData getEdge(KoBorder::BorderSide side) const; KoBorder::BorderStyle getBorderStyle(KoBorder::BorderSide side) const; Q_SIGNALS: void nameChanged(const QString &newName); protected: KoTableCellStylePrivate * const d_ptr; private: /** * Load the style from the \a KoStyleStack style stack using the * OpenDocument format. */ void loadOdfProperties(KoShapeLoadingContext &context, KoStyleStack &styleStack); qreal propertyDouble(int key) const; QPen propertyPen(int key) const; int propertyInt(int key) const; bool propertyBoolean(int key) const; QColor propertyColor(int key) const; /** * Set the format properties from an Edge structure * * @param side defines which edge this is for. * @param style the border style for this side. * @param edge the Edge that hold the properties values */ void setEdge(KoBorder::BorderSide side, const KoBorder::BorderData &edge, KoBorder::BorderStyle style); Q_DECLARE_PRIVATE(KoTableCellStyle) }; Q_DECLARE_METATYPE(KoTableCellStyle *) #endif diff --git a/plugins/flake/textshape/textlayout/AnchorStrategy.h b/plugins/flake/textshape/textlayout/AnchorStrategy.h index b1c139275b..597fada8d2 100644 --- a/plugins/flake/textshape/textlayout/AnchorStrategy.h +++ b/plugins/flake/textshape/textlayout/AnchorStrategy.h @@ -1,112 +1,112 @@ /* This file is part of the KDE project * Copyright (C) 2011 Matus Hanzes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef ANCHORSTRATEGY_H_ #define ANCHORSTRATEGY_H_ #include "KoShapeAnchor.h" #include class KoTextShapeContainerModel; class KoTextLayoutRootArea; class AnchorStrategy : public KoShapeAnchor::PlacementStrategy { public: AnchorStrategy(KoShapeAnchor *anchor, KoTextLayoutRootArea *rootArea); ~AnchorStrategy() override; /** * Moves the subject to it's right position. * * @return true if subject was moved to a new position (or if it couldn't be calculated yet) */ virtual bool moveSubject() = 0; void detachFromModel() override; /** * Reparent the anchored shape under the rootArea's container this AnchorStrategy acts for - .* + * * If needed changes the parent KoShapeContainerModel and KoShapeContainer of the anchored shape. * It is changed so the anchored shape is now under the rootArea */ void updateContainerModel() override; /// get page rectangle coordinates to which this text anchor is anchored (needed for HPage) QRectF pageRect() const; /// set page rectangle coordinates to which this text anchor is anchored (needed for HPage) void setPageRect(const QRectF &pageRect); /// get content rectangle coordinates to which this text anchor is anchored (needed for /// HPageContent) QRectF pageContentRect() const; /// set content rectangle coordinates to which this text anchor is anchored (needed for /// HPageContent) void setPageContentRect(const QRectF &marginRect); /// get paragraph rectangle coordinates to which this text anchor is anchored (needed for /// HParagraphContent, HParagraphStartMargin, HParagraphEndMargin, VParagraph) QRectF paragraphRect() const; /// set paragraph rectangle to which this text anchor is anchored (needed for HParagraphContent, /// HParagraphStartMargin, HParagraphEndMargin, VParagraph) void setParagraphRect(const QRectF ¶graphRect); /// get paragraph rectangle coordinates to which this text anchor is anchored (needed for /// HParagraphContent, HParagraphStartMargin, HParagraphEndMargin) QRectF paragraphContentRect() const; /// set paragraph rectangle to which this text anchor is anchored (needed for HParagraphContent, /// HParagraphStartMargin, HParagraphEndMargin) void setParagraphContentRect(const QRectF ¶graphContentRect); /// get layout environment rectangle @see odf attribute style:flow-with-text QRectF layoutEnvironmentRect() const; /// set layout environment rect @see odf attribute style:flow-with-text void setLayoutEnvironmentRect(const QRectF &layoutEnvironmentRect); /// get number of page to which this text anchor is anchored (needed for HOutside, HInside, /// HFromInside) int pageNumber() const; /// set number of page to which this text anchor is anchored (needed for HOutside, HInside, /// HFromInside) void setPageNumber(int pageNumber); protected: KoShapeAnchor * const m_anchor; KoTextLayoutRootArea *m_rootArea; private: KoTextShapeContainerModel *m_model; QRectF m_pageRect; QRectF m_pageContentRect; QRectF m_paragraphRect; QRectF m_paragraphContentRect; QRectF m_layoutEnvironmentRect; int m_pageNumber; }; #endif /* ANCHORSTRATEGY_H_ */ diff --git a/plugins/flake/textshape/textlayout/KoTextLayoutArea_paint.cpp b/plugins/flake/textshape/textlayout/KoTextLayoutArea_paint.cpp index 567cd76b8c..ff90af68da 100644 --- a/plugins/flake/textshape/textlayout/KoTextLayoutArea_paint.cpp +++ b/plugins/flake/textshape/textlayout/KoTextLayoutArea_paint.cpp @@ -1,1200 +1,1200 @@ /* This file is part of the KDE project * Copyright (C) 2006-2010 Thomas Zander * Copyright (C) 2008 Thorsten Zachmann * Copyright (C) 2008 Girish Ramakrishnan * Copyright (C) 2008 Roopesh Chander * Copyright (C) 2007-2008 Pierre Ducroquet * Copyright (C) 2009-2011 KO GmbH * Copyright (C) 2009-2012 C. Boemann * Copyright (C) 2010 Nandita Suri * Copyright (C) 2010 Ajay Pundhir * Copyright (C) 2011 Lukáš Tvrdý * Copyright (C) 2011 Gopalakrishna Bhat A * Copyright (C) 2011 Stuart Dickson * Copyright (C) 2014 Denis Kuplyakov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoTextLayoutArea.h" #include "KoTextLayoutEndNotesArea.h" #include "KoTextLayoutTableArea.h" #include "KoTextLayoutNoteArea.h" #include "TableIterator.h" #include "ListItemsHelper.h" #include "RunAroundHelper.h" #include "KoTextDocumentLayout.h" #include "FrameIterator.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 "kis_painting_tweaks.h" extern int qt_defaultDpiY(); Q_DECLARE_METATYPE(QTextDocument *) #define DropCapsAdditionalFormattingId 25602902 #include "KoTextLayoutArea_p.h" void KoTextLayoutArea::paint(QPainter *painter, const KoTextDocumentLayout::PaintContext &context) { if (d->startOfArea == 0 || d->endOfArea == 0) // We have not been layouted yet return; /* struct Timer { QTime d->time; Timer() { d->time.start(); } ~Timer() { warnTextLayout << "elapsed=" << d->time.elapsed(); } }; Timer timer; */ painter->save(); painter->translate(0, d->verticalAlignOffset); painter->setPen(context.textContext.palette.color(QPalette::Text)); // for text that has no color. const QRegion clipRegion = KisPaintingTweaks::safeClipRegion(*painter); // fetch after painter->translate so the clipRegion is correct KoTextBlockBorderData *lastBorder = 0; QRectF lastBorderRect; QTextFrame::iterator it = d->startOfArea->it; QTextFrame::iterator stop = d->endOfArea->it; if (!stop.atEnd()) { if (!stop.currentBlock().isValid() || d->endOfArea->lineTextStart >= 0) { // Last thing we show is a frame (table) or first part of a paragraph split in two // The stop point should be the object after that // However if stop is already atEnd we shouldn't increment further ++stop; } } int tableAreaIndex = 0; int blockIndex = 0; int tocIndex = 0; for (; it != stop && !it.atEnd(); ++it) { QTextBlock block = it.currentBlock(); QTextTable *table = qobject_cast(it.currentFrame()); QTextFrame *subFrame = it.currentFrame(); QTextBlockFormat format = block.blockFormat(); if (!block.isValid()) { if (lastBorder) { // draw previous block's border lastBorder->paint(*painter, lastBorderRect); lastBorder = 0; } } if (table) { if (tableAreaIndex >= d->tableAreas.size()) { continue; } d->tableAreas[tableAreaIndex]->paint(painter, context); ++tableAreaIndex; continue; } else if (subFrame) { if (subFrame->format().intProperty(KoText::SubFrameType) == KoText::AuxillaryFrameType) { d->endNotesArea->paint(painter, context); } continue; } else { if (!block.isValid()) { continue; } } if (block.blockFormat().hasProperty(KoParagraphStyle::GeneratedDocument)) { // Possibly paint the selection of the entire Table of Contents // but since it's a secondary document we need to create a fake selection QVariant data = block.blockFormat().property(KoParagraphStyle::GeneratedDocument); QTextDocument *generatedDocument = data.value(); KoTextDocumentLayout::PaintContext tocContext = context; tocContext.textContext.selections = QVector(); bool pure = true; Q_FOREACH (const QAbstractTextDocumentLayout::Selection &selection, context.textContext.selections) { if (selection.cursor.selectionStart() <= block.position() && selection.cursor.selectionEnd() >= block.position()) { painter->fillRect(d->generatedDocAreas[tocIndex]->boundingRect(), selection.format.background()); if (pure) { tocContext.textContext.selections.append(QAbstractTextDocumentLayout::Selection()); tocContext.textContext.selections[0].cursor = QTextCursor(generatedDocument); tocContext.textContext.selections[0].cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); tocContext.textContext.selections[0].format = selection.format; pure = false; } } } d->generatedDocAreas[tocIndex]->paint(painter, tocContext); ++tocIndex; continue; } QTextLayout *layout = block.layout(); KoTextBlockBorderData *border = 0; if (blockIndex >= d->blockRects.count()) break; QRectF br = d->blockRects[blockIndex]; ++blockIndex; if (!painter->hasClipping() || clipRegion.intersects(br.toRect())) { KoTextBlockData blockData(block); border = blockData.border(); KoTextBlockPaintStrategyBase *paintStrategy = blockData.paintStrategy(); KoTextBlockPaintStrategyBase dummyPaintStrategy; if (paintStrategy == 0) { paintStrategy = &dummyPaintStrategy; } if (!paintStrategy->isVisible()) { if (lastBorder) { // draw previous block's border lastBorder->paint(*painter, lastBorderRect); lastBorder = 0; } continue; // this paragraph shouldn't be shown so just skip it } // Check and update border drawing code if (lastBorder == 0) { lastBorderRect = br; } else if (lastBorder != border || lastBorderRect.width() != br.width() || lastBorderRect.x() != br.x()) { lastBorder->paint(*painter, lastBorderRect); lastBorderRect = br; } else { lastBorderRect = lastBorderRect.united(br); } lastBorder = border; painter->save(); QBrush bg = paintStrategy->background(block.blockFormat().background()); if (bg != Qt::NoBrush ) { painter->fillRect(br, bg); } else { bg = context.background; } paintStrategy->applyStrategy(painter); painter->save(); drawListItem(painter, block); painter->restore(); QVector selections; if (context.showSelections) { Q_FOREACH (const QAbstractTextDocumentLayout::Selection & selection, context.textContext.selections) { QTextCursor cursor = selection.cursor; int begin = cursor.position(); int end = cursor.anchor(); if (begin > end) std::swap(begin, end); if (end < block.position() || begin > block.position() + block.length()) continue; // selection does not intersect this block. if (selection.cursor.hasComplexSelection()) { continue; // selections of several table cells are covered by the within drawBorders above. } if (d->documentLayout->changeTracker() && !d->documentLayout->changeTracker()->displayChanges() && d->documentLayout->changeTracker()->containsInlineChanges(selection.format) && d->documentLayout->changeTracker()->elementById(selection.format.property(KoCharacterStyle::ChangeTrackerId).toInt())->isEnabled() && d->documentLayout->changeTracker()->elementById(selection.format.property(KoCharacterStyle::ChangeTrackerId).toInt())->getChangeType() == KoGenChange::DeleteChange) { continue; // Deletions should not be shown. } QTextLayout::FormatRange fr; fr.start = begin - block.position(); fr.length = end - begin; fr.format = selection.format; selections.append(fr); } } // this is a workaround to fix text getting cut of when format ranges are used. There // is a bug in Qt that can hit when text lines overlap each other. In case a format range // is used for formatting it can clip the lines above/below as Qt creates a clip rect for // the places it already painted for the format range which results in clippling. So use // the format range always to paint the text. QVector workaroundFormatRanges; for (QTextBlock::iterator it = block.begin(); !(it.atEnd()); ++it) { QTextFragment currentFragment = it.fragment(); if (currentFragment.isValid()) { bool formatChanged = false; QTextCharFormat format = currentFragment.charFormat(); int changeId = format.intProperty(KoCharacterStyle::ChangeTrackerId); if (changeId && d->documentLayout->changeTracker() && d->documentLayout->changeTracker()->displayChanges()) { KoChangeTrackerElement *changeElement = d->documentLayout->changeTracker()->elementById(changeId); switch(changeElement->getChangeType()) { case (KoGenChange::InsertChange): format.setBackground(QBrush(d->documentLayout->changeTracker()->getInsertionBgColor())); break; case (KoGenChange::FormatChange): format.setBackground(QBrush(d->documentLayout->changeTracker()->getFormatChangeBgColor())); break; case (KoGenChange::DeleteChange): format.setBackground(QBrush(d->documentLayout->changeTracker()->getDeletionBgColor())); break; case (KoGenChange::UNKNOWN): break; } formatChanged = true; } if (format.isAnchor()) { if (!format.hasProperty(KoCharacterStyle::UnderlineStyle)) format.setFontUnderline(true); if (!format.hasProperty(QTextFormat::ForegroundBrush)) format.setForeground(Qt::blue); formatChanged = true; } if (format.boolProperty(KoCharacterStyle::UseWindowFontColor)) { QBrush backbrush = bg; if (format.background() != Qt::NoBrush) { backbrush = format.background(); } QBrush frontBrush; frontBrush.setStyle(Qt::SolidPattern); // use the same luma calculation and threshold as msoffice // see http://social.msdn.microsoft.com/Forums/en-US/os_binaryfile/thread/a02a9a24-efb6-4ba0-a187-0e3d2704882b int luma = ((5036060/2) * backbrush.color().red() + (9886846/2) * backbrush.color().green() + (1920103/2) * backbrush.color().blue()) >> 23; if (luma > 60) { frontBrush.setColor(QColor(Qt::black)); } else { frontBrush.setColor(QColor(Qt::white)); } format.setForeground(frontBrush); formatChanged = true; } if (formatChanged) { QTextLayout::FormatRange fr; fr.start = currentFragment.position() - block.position(); fr.length = currentFragment.length(); if (!format.hasProperty(KoCharacterStyle::InlineInstanceId)) { if (format.background().style() == Qt::NoBrush) { format.setBackground(QBrush(QColor(0, 0, 0, 0))); } if (format.foreground().style() == Qt::NoBrush) { format.setForeground(QBrush(QColor(0, 0, 0))); } } fr.format = format; // the prepend is done so the selections are at the end. selections.prepend(fr); } else { if (!format.hasProperty(KoCharacterStyle::InlineInstanceId)) { QTextLayout::FormatRange fr; fr.start = currentFragment.position() - block.position(); fr.length = currentFragment.length(); QTextCharFormat f; if (format.background().style() == Qt::NoBrush) { f.setBackground(QBrush(QColor(0, 0, 0, 0))); } else { f.setBackground(format.background()); } if (format.foreground().style() == Qt::NoBrush) { f.setForeground(QBrush(QColor(0, 0, 0))); } else { f.setForeground(format.foreground()); } fr.format = f; workaroundFormatRanges.append(fr); } } } } if (!selections.isEmpty()) { selections = workaroundFormatRanges + selections; } //We set clip because layout-draw doesn't clip text to it correctly after all //and adjust to make sure we don't clip edges of glyphs. The clipping is //important for paragraph split across two pages. //20pt enlargement seems safe as pages is split by 50pt and this helps unwanted //glyph cutting painter->setClipRect(br.adjusted(-20,-20,20,20), Qt::IntersectClip); layout->draw(painter, QPointF(0, 0), selections); if (context.showSectionBounds) { decorateParagraphSections(painter, block); } decorateParagraph(painter, block, context.showFormattingCharacters, context.showSpellChecking); painter->restore(); } else { if (lastBorder) { lastBorder->paint(*painter, lastBorderRect); lastBorder = 0; } } } if (lastBorder) { lastBorder->paint(*painter, lastBorderRect); } painter->translate(0, -d->verticalAlignOffset); painter->translate(0, bottom() - d->footNotesHeight); Q_FOREACH (KoTextLayoutNoteArea *footerArea, d->footNoteAreas) { footerArea->paint(painter, context); painter->translate(0, footerArea->bottom() - footerArea->top()); } painter->restore(); } void KoTextLayoutArea::drawListItem(QPainter *painter, QTextBlock &block) { KoTextBlockData blockData(block); QTextList *list = block.textList(); if (list && blockData.hasCounterData()) { QTextListFormat listFormat = list->format(); if (! blockData.counterText().isEmpty()) { QFont font(blockData.labelFormat().font(), d->documentLayout->paintDevice()); KoListStyle::Style listStyle = static_cast(listFormat.style()); QString result = blockData.counterText(); QTextLayout layout(result, font, d->documentLayout->paintDevice()); QList layouts; QTextLayout::FormatRange format; format.start = 0; format.length = blockData.counterText().length(); format.format = blockData.labelFormat(); layouts.append(format); layout.setAdditionalFormats(layouts); Qt::Alignment alignment = static_cast(listFormat.intProperty(KoListStyle::Alignment)); if (alignment == 0) { alignment = Qt::AlignLeft | Qt::AlignAbsolute; } if (d->isRtl && (alignment & Qt::AlignAbsolute) == 0) { if (alignment & Qt::AlignLeft) { alignment = Qt::AlignRight; } else if (alignment & Qt::AlignRight) { alignment = Qt::AlignLeft; } } alignment |= Qt::AlignAbsolute; QTextOption option(alignment); option.setTextDirection(block.layout()->textOption().textDirection()); /* if (option.textDirection() == Qt::RightToLeft || blockData.counterText().isRightToLeft()) { option.setAlignment(Qt::AlignRight); } */ layout.setTextOption(option); layout.beginLayout(); QTextLine line = layout.createLine(); line.setLineWidth(blockData.counterWidth()); layout.endLayout(); QPointF counterPosition = blockData.counterPosition(); if (block.layout()->lineCount() > 0) { // if there is text, then baseline align the counter. QTextLine firstParagLine = block.layout()->lineAt(0); if (KoListStyle::isNumberingStyle(listStyle)) { //if numbered list baseline align counterPosition += QPointF(0, firstParagLine.ascent() - layout.lineAt(0).ascent()); } else { //for unnumbered list center align counterPosition += QPointF(0, (firstParagLine.height() - layout.lineAt(0).height())/2.0); } } layout.draw(painter, counterPosition); //decorate the list label iff it is a numbered list if (KoListStyle::isNumberingStyle(listStyle)) { painter->save(); decorateListLabel(painter, blockData, layout.lineAt(0), block); painter->restore(); } } KoListStyle::Style listStyle = static_cast(listFormat.style()); if (listStyle == KoListStyle::ImageItem) { QFontMetricsF fm(blockData.labelFormat().font(), d->documentLayout->paintDevice()); qreal x = qMax(qreal(1), blockData.counterPosition().x()); qreal width = qMax(listFormat.doubleProperty(KoListStyle::Width), (qreal)1.0); qreal height = qMax(listFormat.doubleProperty(KoListStyle::Height), (qreal)1.0); qreal y = blockData.counterPosition().y() + fm.ascent() - fm.xHeight()/2 - height/2; // centered KoImageData *idata = listFormat.property(KoListStyle::BulletImage).value(); if (idata) { painter->drawPixmap(x, y, width, height, idata->pixmap()); } } } } void KoTextLayoutArea::decorateListLabel(QPainter *painter, const KoTextBlockData &blockData, const QTextLine &listLabelLine, const QTextBlock &listItem) { const QTextCharFormat listLabelCharFormat = blockData.labelFormat(); painter->setFont(listLabelCharFormat.font()); int startOfFragmentInBlock = 0; Q_ASSERT_X(listLabelLine.isValid(), __FUNCTION__, QString("Invalid list label").toLocal8Bit()); if (!listLabelLine.isValid()) { return; } int fragmentToLineOffset = 0; qreal x1 = blockData.counterPosition().x(); qreal x2 = listItem.layout()->lineAt(0).x(); if (x2 != x1) { drawStrikeOuts(painter, listLabelCharFormat, blockData.counterText(), listItem.layout()->lineAt(0), x1, x2, startOfFragmentInBlock, fragmentToLineOffset); drawOverlines(painter, listLabelCharFormat, blockData.counterText(), listItem.layout()->lineAt(0), x1, x2, startOfFragmentInBlock, fragmentToLineOffset); drawUnderlines(painter, listLabelCharFormat, blockData.counterText(), listItem.layout()->lineAt(0), x1, x2, startOfFragmentInBlock, fragmentToLineOffset); } } /** * Draw a line. Typically meant to underline text or similar. * @param painter the painter to paint on. - * @painter color the pen color to for the decoratoin line + * @param color the pen color to for the decoration line * @param type The type * @param style the type of line to draw. * @param width The thickness of the line, in pixels (the painter will be prescaled to points coordinate system). * @param x1 we are always drawing horizontal lines, this is the start point. * @param x2 we are always drawing horizontal lines, this is the end point. * @param y the y-offset to paint on. */ static void drawDecorationLine(QPainter *painter, const QColor &color, KoCharacterStyle::LineType type, KoCharacterStyle::LineStyle style, qreal width, const qreal x1, const qreal x2, const qreal y) { QPen penBackup = painter->pen(); QPen pen = painter->pen(); pen.setColor(color); pen.setWidthF(width); if (style == KoCharacterStyle::WaveLine) { // Ok, try the waves :) pen.setStyle(Qt::SolidLine); painter->setPen(pen); qreal x = x1; const qreal halfWaveWidth = 0.5 * width; const qreal halfWaveLength = 2 * width; const int startAngle = 0 * 16; const int middleAngle = 180 * 16; const int endAngle = 180 * 16; while (x < x2) { QRectF rectangle1(x, y, halfWaveLength, 2*halfWaveWidth); if (type == KoCharacterStyle::DoubleLine) { painter->translate(0, -pen.width()); painter->drawArc(rectangle1, startAngle, middleAngle); painter->translate(0, 2*pen.width()); painter->drawArc(rectangle1, startAngle, middleAngle); painter->translate(0, -pen.width()); } else { painter->drawArc(rectangle1, startAngle, middleAngle); } if (x + halfWaveLength > x2) break; QRectF rectangle2(x + halfWaveLength, y, halfWaveLength, 2*halfWaveWidth); if (type == KoCharacterStyle::DoubleLine) { painter->translate(0, -pen.width()); painter->drawArc(rectangle2, middleAngle, endAngle); painter->translate(0, 2*pen.width()); painter->drawArc(rectangle2, middleAngle, endAngle); painter->translate(0, -pen.width()); } else { painter->drawArc(rectangle2, middleAngle, endAngle); } x = x + 2 * halfWaveLength; } } else { if (style == KoCharacterStyle::LongDashLine) { QVector dashes; dashes << 12 << 2; pen.setDashPattern(dashes); } else { pen.setStyle((Qt::PenStyle)style); } painter->setPen(pen); if (type == KoCharacterStyle::DoubleLine) { painter->translate(0, -pen.width()); painter->drawLine(QPointF(x1, y), QPointF(x2, y)); painter->translate(0, 2*pen.width()); painter->drawLine(QPointF(x1, y), QPointF(x2, y)); painter->translate(0, -pen.width()); } else { painter->drawLine(QPointF(x1, y), QPointF(x2, y)); } } painter->setPen(penBackup); } static void drawDecorationText(QPainter *painter, const QTextLine &line, const QColor &color, const QString& decorText, qreal x1, qreal x2) { qreal y = line.position().y(); QPen oldPen = painter->pen(); painter->setPen(QPen(color)); do { QRectF br; painter->drawText(QRectF(QPointF(x1, y), QPointF(x2, y + line.height())), Qt::AlignLeft | Qt::AlignVCenter, decorText, &br); x1 = br.right(); } while (x1 <= x2); painter->setPen(oldPen); } static void drawDecorationWords(QPainter *painter, const QTextLine &line, const QString &text, const QColor &color, KoCharacterStyle::LineType type, KoCharacterStyle::LineStyle style, const QString& decorText, qreal width, const qreal y, const int fragmentToLineOffset, const int startOfFragmentInBlock) { qreal wordBeginX = -1; int j = line.textStart()+fragmentToLineOffset; while (j < line.textLength() + line.textStart() && j-startOfFragmentInBlockpen(); QPen pen = painter->pen(); pen.setWidth(1); pen.setColor(Qt::gray); painter->setPen(pen); qreal xl = layout->boundingRect().left(); qreal xr = qMax(layout->boundingRect().right(), layout->boundingRect().left() + width()); qreal yu = layout->boundingRect().top(); qreal yd = layout->boundingRect().bottom(); qreal bracketSize = painter->fontMetrics().height() / 2; const qreal levelShift = 3; QList openList = KoSectionUtils::sectionStartings(bf); for (int i = 0; i < openList.size(); i++) { int sectionLevel = openList[i]->level(); if (i == 0) { painter->drawLine(xl + sectionLevel * levelShift, yu, xr - sectionLevel * levelShift, yu); } painter->drawLine(xl + sectionLevel * levelShift, yu, xl + sectionLevel * levelShift, yu + bracketSize); painter->drawLine(xr - sectionLevel * levelShift, yu, xr - sectionLevel * levelShift, yu + bracketSize); } QList closeList = KoSectionUtils::sectionEndings(bf); for (int i = 0; i < closeList.size(); i++) { int sectionLevel = closeList[i]->correspondingSection()->level(); if (i == closeList.count() - 1) { painter->drawLine(xl + sectionLevel * levelShift, yd, xr - sectionLevel * levelShift, yd); } painter->drawLine(xl + sectionLevel * levelShift, yd, xl + sectionLevel * levelShift, yd - bracketSize); painter->drawLine(xr - sectionLevel * levelShift, yd, xr - sectionLevel * levelShift, yd - bracketSize); } painter->setPen(penBackup); } void KoTextLayoutArea::decorateParagraph(QPainter *painter, QTextBlock &block, bool showFormattingCharacters, bool showSpellChecking) { QTextLayout *layout = block.layout(); QTextBlockFormat bf = block.blockFormat(); QVariantList tabList = bf.property(KoParagraphStyle::TabPositions).toList(); QFont oldFont = painter->font(); QTextBlock::iterator it; int startOfBlock = -1; int currentTabStop = 0; // qDebug() << "\n-------------------" // << "\nGoing to decorate block\n" // << block.text() // << "\n-------------------"; // loop over text fragments in this paragraph and draw the underline and line through. for (it = block.begin(); !it.atEnd(); ++it) { QTextFragment currentFragment = it.fragment(); if (currentFragment.isValid()) { // qDebug() << "\tGoing to layout fragment:" << currentFragment.text(); QTextCharFormat fmt = currentFragment.charFormat(); painter->setFont(fmt.font()); // a block doesn't have a real start position, so use our own counter. Initialize // it with the position of the first text fragment in the block. if (startOfBlock == -1) { startOfBlock = currentFragment.position(); // start of this block w.r.t. the document } // the start of our fragment in the block is the absolute position of the fragment // in the document minus the start of the block in the document. int startOfFragmentInBlock = currentFragment.position() - startOfBlock; // a fragment can span multiple lines, but we paint the decorations per line. int firstLine = layout->lineForTextPosition(currentFragment.position() - startOfBlock).lineNumber(); int lastLine = layout->lineForTextPosition(currentFragment.position() + currentFragment.length() - startOfBlock).lineNumber(); // qDebug() << "\tfirst line:" << firstLine << "last line:" << lastLine; for (int i = firstLine ; i <= lastLine ; ++i) { QTextLine line = layout->lineAt(i); // qDebug() << "\n\t\tcurrent line:" << i // << "\n\t\tline length:" << line.textLength() << "width:"<< line.width() << "natural width" << line.naturalTextWidth() // << "\n\t\tvalid:" << layout->isValidCursorPosition(currentFragment.position() - startOfBlock) // << "\n\t\tcurrentFragment.position:" << currentFragment.position() // << "\n\t\tstartOfBlock:" << startOfBlock // << "\n\t\tstartOfFragmentInBlock:" << startOfFragmentInBlock; if (layout->isValidCursorPosition(currentFragment.position() - startOfBlock)) { // the start position for painting the decoration is the position of the fragment // inside, but after the first line, the decoration always starts at the beginning // of the line. See bug: 264471 int p1 = startOfFragmentInBlock; if (i > firstLine) { p1 = line.textStart(); } // qDebug() << "\n\t\tblock.text.length:" << block.text().length() << "p1" << p1; if (block.text().length() > p1 && block.text().at(p1) != QChar::ObjectReplacementCharacter) { Q_ASSERT_X(line.isValid(), __FUNCTION__, QString("Invalid line=%1 first=%2 last=%3").arg(i).arg(firstLine).arg(lastLine).toLocal8Bit()); // see bug 278682 if (!line.isValid()) continue; // end position: note that x2 can be smaller than x1 when we are handling RTL int p2 = startOfFragmentInBlock + currentFragment.length(); int lineEndWithoutPreedit = line.textStart() + line.textLength(); if (block.layout()->preeditAreaPosition() >= block.position() + line.textStart() && block.layout()->preeditAreaPosition() <= block.position() + line.textStart() + line.textLength()) { lineEndWithoutPreedit -= block.layout()->preeditAreaText().length(); } while (lineEndWithoutPreedit > line.textStart() && block.text().at(lineEndWithoutPreedit - 1) == ' ') { --lineEndWithoutPreedit; } if (lineEndWithoutPreedit < p2) { //line caps p2 = lineEndWithoutPreedit; } int fragmentToLineOffset = qMax(startOfFragmentInBlock - line.textStart(), 0); qreal x1 = line.cursorToX(p1); qreal x2 = line.cursorToX(p2); //qDebug() << "\n\t\t\tp1:" << p1 << "x1:" << x1 // << "\n\t\t\tp2:" << p2 << "x2:" << x2 // << "\n\t\t\tlineEndWithoutPreedit" << lineEndWithoutPreedit; if (x1 != x2) { drawStrikeOuts(painter, fmt, currentFragment.text(), line, x1, x2, startOfFragmentInBlock, fragmentToLineOffset); drawOverlines(painter, fmt, currentFragment.text(), line, x1, x2, startOfFragmentInBlock, fragmentToLineOffset); drawUnderlines(painter, fmt, currentFragment.text(), line, x1, x2, startOfFragmentInBlock, fragmentToLineOffset); } decorateTabsAndFormatting(painter, currentFragment, line, startOfFragmentInBlock, tabList, currentTabStop, showFormattingCharacters); // underline preedit strings if (layout->preeditAreaPosition() > -1) { int start = block.layout()->preeditAreaPosition(); int end = block.layout()->preeditAreaPosition() + block.layout()->preeditAreaText().length(); QTextCharFormat underline; underline.setFontUnderline(true); underline.setUnderlineStyle(QTextCharFormat::DashUnderline); //qDebug() << "underline style" << underline.underlineStyle(); //qDebug() << "line start: " << block.position() << line.textStart(); qreal z1 = 0; qreal z2 = 0; // preedit start in this line, end in this line if ( start >= block.position() + line.textStart() && end <= block.position() + line.textStart() + line.textLength() ) { z1 = line.cursorToX(start); z2 = line.cursorToX(end); } // preedit start in this line, end after this line if ( start >= block.position() + line.textStart() && end > block.position() + line.textStart() + line.textLength() ) { z1 = line.cursorToX(start); z2 = line.cursorToX(block.position() + line.textStart() + line.textLength()); } // preedit start before this line, end in this line if ( start < block.position() + line.textStart() && end <= block.position() + line.textStart() + line.textLength() ) { z1 = line.cursorToX(block.position() + line.textStart()); z2 = line.cursorToX(end); } // preedit start before this line, end after this line if ( start < block.position() + line.textStart() && end > block.position() + line.textStart() + line.textLength() ) { z1 = line.cursorToX(block.position() + line.textStart()); z2 = line.cursorToX(block.position() + line.textStart() + line.textLength()); } if (z2 > z1) { //qDebug() << "z1: " << z1 << "z2: " << z2; KoCharacterStyle::LineStyle fontUnderLineStyle = KoCharacterStyle::DashLine; KoCharacterStyle::LineType fontUnderLineType = KoCharacterStyle::SingleLine; QTextCharFormat::VerticalAlignment valign = fmt.verticalAlignment(); QFont font(fmt.font()); if (valign == QTextCharFormat::AlignSubScript || valign == QTextCharFormat::AlignSuperScript) font.setPointSize(font.pointSize() * 2 / 3); QFontMetricsF metrics(font, d->documentLayout->paintDevice()); qreal y = line.position().y(); if (valign == QTextCharFormat::AlignSubScript) y += line.height() - metrics.descent() + metrics.underlinePos(); else if (valign == QTextCharFormat::AlignSuperScript) y += metrics.ascent() + metrics.underlinePos(); else y += line.ascent() + metrics.underlinePos(); QColor color = fmt.foreground().color(); qreal width = computeWidth( // line thickness (KoCharacterStyle::LineWeight) underline.intProperty(KoCharacterStyle::UnderlineWeight), underline.doubleProperty(KoCharacterStyle::UnderlineWidth), font); if (valign == QTextCharFormat::AlignSubScript || valign == QTextCharFormat::AlignSuperScript) // adjust size. width = width * 2 / 3; drawDecorationLine(painter, color, fontUnderLineType, fontUnderLineStyle, width, z1, z2, y); } } } } } } } if (showFormattingCharacters) { QTextLine line = layout->lineForTextPosition(block.length()-1); qreal y = line.position().y() + line.ascent(); qreal x = line.cursorToX(block.length()-1); painter->drawText(QPointF(x, y), QChar((ushort)0x00B6)); } if (showSpellChecking) { // Finally let's paint our own spelling markings // TODO Should we make this optional at this point (right on/off handled by the plugin) // also we might want to provide alternative ways of drawing it KoTextBlockData blockData(block); QPen penBackup = painter->pen(); QPen pen; pen.setColor(QColor(Qt::red)); pen.setWidthF(1.5); QVector pattern; pattern << 1 << 2; pen.setDashPattern(pattern); painter->setPen(pen); QList::Iterator markIt = blockData.markupsBegin(KoTextBlockData::Misspell); QList::Iterator markEnd = blockData.markupsEnd(KoTextBlockData::Misspell); for (int i = 0 ; i < layout->lineCount(); ++i) { if (markIt == markEnd) { break; } QTextLine line = layout->lineAt(i); // the y position is placed half way between baseline and descent of the line // this is fast and sufficient qreal y = line.position().y() + line.ascent() + 0.5 * line.descent(); // first handle all those marking ranges that end on this line while (markIt != markEnd && markIt->lastChar < line.textStart() + line.textLength() && line.textStart() + line.textLength() <= block.length()) { if (!blockData.isMarkupsLayoutValid(KoTextBlockData::Misspell)) { if (markIt->firstChar > line.textStart()) { markIt->startX = line.cursorToX(markIt->firstChar); } markIt->endX = line.cursorToX(qMin(markIt->lastChar, block.length())); } qreal x1 = (markIt->firstChar > line.textStart()) ? markIt->startX : line.cursorToX(0); painter->drawLine(QPointF(x1, y), QPointF(markIt->endX, y)); ++markIt; } // there may be a markup range on this line that extends to the next line if (markIt != markEnd && markIt->firstChar < line.textStart() + line.textLength() && line.textStart() + line.textLength() <= block.length()) { if (!blockData.isMarkupsLayoutValid(KoTextBlockData::Misspell)) { if (markIt->firstChar > line.textStart()) { markIt->startX = line.cursorToX(markIt->firstChar); } } qreal x1 = (markIt->firstChar > line.textStart()) ? markIt->startX : line.cursorToX(0); painter->drawLine(QPointF(x1, y), QPointF(line.cursorToX(line.textStart() + line.textLength()), y)); // since it extends to next line we don't increment the iterator } } blockData.setMarkupsLayoutValidity(KoTextBlockData::Misspell, true); painter->setPen(penBackup); } painter->setFont(oldFont); } void KoTextLayoutArea::drawStrikeOuts(QPainter *painter, const QTextCharFormat ¤tCharFormat, const QString &text, const QTextLine &line, qreal x1, qreal x2, const int startOfFragmentInBlock, const int fragmentToLineOffset) const { KoCharacterStyle::LineStyle strikeOutStyle = (KoCharacterStyle::LineStyle) currentCharFormat.intProperty(KoCharacterStyle::StrikeOutStyle); KoCharacterStyle::LineType strikeOutType = (KoCharacterStyle::LineType) currentCharFormat.intProperty(KoCharacterStyle::StrikeOutType); if ((strikeOutStyle != KoCharacterStyle::NoLineStyle) && (strikeOutType != KoCharacterStyle::NoLineType)) { QTextCharFormat::VerticalAlignment valign = currentCharFormat.verticalAlignment(); QFont font(currentCharFormat.font()); if (valign == QTextCharFormat::AlignSubScript || valign == QTextCharFormat::AlignSuperScript) font.setPointSize(qRound(font.pointSize() * 2 / 3.)); QFontMetricsF metrics(font, d->documentLayout->paintDevice()); qreal y = line.position().y(); if (valign == QTextCharFormat::AlignSubScript) y += line.height() - metrics.descent() - metrics.strikeOutPos(); else if (valign == QTextCharFormat::AlignSuperScript) y += metrics.ascent() - metrics.strikeOutPos(); else y += line.ascent() - metrics.strikeOutPos(); QColor color = currentCharFormat.colorProperty(KoCharacterStyle::StrikeOutColor); if (!color.isValid()) color = currentCharFormat.foreground().color(); KoCharacterStyle::LineMode strikeOutMode = (KoCharacterStyle::LineMode) currentCharFormat.intProperty(KoCharacterStyle::StrikeOutMode); QString strikeOutText = currentCharFormat.stringProperty(KoCharacterStyle::StrikeOutText); qreal width = 0; // line thickness if (strikeOutText.isEmpty()) { width = computeWidth( (KoCharacterStyle::LineWeight) currentCharFormat.intProperty(KoCharacterStyle::StrikeOutWeight), currentCharFormat.doubleProperty(KoCharacterStyle::StrikeOutWidth), font); } if (valign == QTextCharFormat::AlignSubScript || valign == QTextCharFormat::AlignSuperScript) // adjust size. width = width * 2 / 3; if (strikeOutMode == KoCharacterStyle::SkipWhiteSpaceLineMode) { drawDecorationWords(painter, line, text, color, strikeOutType, strikeOutStyle, strikeOutText, width, y, fragmentToLineOffset, startOfFragmentInBlock); } else { if (strikeOutText.isEmpty()) drawDecorationLine(painter, color, strikeOutType, strikeOutStyle, width, x1, x2, y); else drawDecorationText(painter, line, color, strikeOutText, x1, x2); } } } void KoTextLayoutArea::drawOverlines(QPainter *painter, const QTextCharFormat ¤tCharFormat, const QString &text, const QTextLine &line, qreal x1, qreal x2, const int startOfFragmentInBlock, const int fragmentToLineOffset) const { KoCharacterStyle::LineStyle fontOverLineStyle = (KoCharacterStyle::LineStyle) currentCharFormat.intProperty(KoCharacterStyle::OverlineStyle); KoCharacterStyle::LineType fontOverLineType = (KoCharacterStyle::LineType) currentCharFormat.intProperty(KoCharacterStyle::OverlineType); if ((fontOverLineStyle != KoCharacterStyle::NoLineStyle) && (fontOverLineType != KoCharacterStyle::NoLineType)) { QTextCharFormat::VerticalAlignment valign = currentCharFormat.verticalAlignment(); QFont font(currentCharFormat.font()); if (valign == QTextCharFormat::AlignSubScript || valign == QTextCharFormat::AlignSuperScript) font.setPointSize(font.pointSize() * 2 / 3); QFontMetricsF metrics(font, d->documentLayout->paintDevice()); qreal y = line.position().y(); if (valign == QTextCharFormat::AlignSubScript) y += line.height() - metrics.descent() - metrics.overlinePos(); else if (valign == QTextCharFormat::AlignSuperScript) y += metrics.ascent() - metrics.overlinePos(); else y += line.ascent() - metrics.overlinePos(); QColor color = currentCharFormat.colorProperty(KoCharacterStyle::OverlineColor); if (!color.isValid()) color = currentCharFormat.foreground().color(); KoCharacterStyle::LineMode overlineMode = (KoCharacterStyle::LineMode) currentCharFormat.intProperty(KoCharacterStyle::OverlineMode); qreal width = computeWidth( // line thickness (KoCharacterStyle::LineWeight) currentCharFormat.intProperty(KoCharacterStyle::OverlineWeight), currentCharFormat.doubleProperty(KoCharacterStyle::OverlineWidth), font); if (valign == QTextCharFormat::AlignSubScript || valign == QTextCharFormat::AlignSuperScript) // adjust size. width = width * 2 / 3; if (overlineMode == KoCharacterStyle::SkipWhiteSpaceLineMode) { drawDecorationWords(painter, line, text, color, fontOverLineType, fontOverLineStyle, QString(), width, y, fragmentToLineOffset, startOfFragmentInBlock); } else { drawDecorationLine(painter, color, fontOverLineType, fontOverLineStyle, width, x1, x2, y); } } } void KoTextLayoutArea::drawUnderlines(QPainter *painter, const QTextCharFormat ¤tCharFormat,const QString &text, const QTextLine &line, qreal x1, qreal x2, const int startOfFragmentInBlock, const int fragmentToLineOffset) const { KoCharacterStyle::LineStyle fontUnderLineStyle = (KoCharacterStyle::LineStyle) currentCharFormat.intProperty(KoCharacterStyle::UnderlineStyle); KoCharacterStyle::LineType fontUnderLineType = (KoCharacterStyle::LineType) currentCharFormat.intProperty(KoCharacterStyle::UnderlineType); if ((fontUnderLineStyle != KoCharacterStyle::NoLineStyle) && (fontUnderLineType != KoCharacterStyle::NoLineType)) { QTextCharFormat::VerticalAlignment valign = currentCharFormat.verticalAlignment(); QFont font(currentCharFormat.font()); if (valign == QTextCharFormat::AlignSubScript || valign == QTextCharFormat::AlignSuperScript) font.setPointSize(font.pointSize() * 2 / 3); QFontMetricsF metrics(font, d->documentLayout->paintDevice()); qreal y = line.position().y(); if (valign == QTextCharFormat::AlignSubScript) y += line.height() - metrics.descent() + metrics.underlinePos(); else if (valign == QTextCharFormat::AlignSuperScript) y += metrics.ascent() + metrics.underlinePos(); else y += line.ascent() + metrics.underlinePos(); QColor color = currentCharFormat.underlineColor(); if (!color.isValid()) color = currentCharFormat.foreground().color(); KoCharacterStyle::LineMode underlineMode = (KoCharacterStyle::LineMode) currentCharFormat.intProperty(KoCharacterStyle::UnderlineMode); qreal width = computeWidth( // line thickness (KoCharacterStyle::LineWeight) currentCharFormat.intProperty(KoCharacterStyle::UnderlineWeight), currentCharFormat.doubleProperty(KoCharacterStyle::UnderlineWidth), font); if (valign == QTextCharFormat::AlignSubScript || valign == QTextCharFormat::AlignSuperScript) // adjust size. width = width * 2 / 3; if (underlineMode == KoCharacterStyle::SkipWhiteSpaceLineMode) { drawDecorationWords(painter, line, text, color, fontUnderLineType, fontUnderLineStyle, QString(), width, y, fragmentToLineOffset, startOfFragmentInBlock); } else { drawDecorationLine(painter, color, fontUnderLineType, fontUnderLineStyle, width, x1, x2, y); } } } // Decorate any tabs ('\t's) in 'currentFragment' and laid out in 'line'. int KoTextLayoutArea::decorateTabsAndFormatting(QPainter *painter, const QTextFragment& currentFragment, const QTextLine &line, const int startOfFragmentInBlock, const QVariantList& tabList, int currentTabStop, bool showFormattingCharacters) { // If a line in the layout represent multiple text fragments, this function will // be called multiple times on the same line, with different fragments. // Likewise, if a fragment spans two lines, then this function will be called twice // on the same fragment, once for each line. QString fragText = currentFragment.text(); QFontMetricsF fm(currentFragment.charFormat().font(), d->documentLayout->paintDevice()); qreal tabStyleLineMargin = fm.averageCharWidth() / 4; // leave some margin for the tab decoration line // currentFragment.position() : start of this fragment w.r.t. the document // startOfFragmentInBlock : start of this fragment w.r.t. the block // line.textStart() : start of this line w.r.t. the block int searchForCharFrom; // search for \t from this point onwards in fragText int searchForCharTill; // search for \t till this point in fragText if (line.textStart() >= startOfFragmentInBlock) { // fragment starts at or before the start of line // we are concerned with only that part of the fragment displayed in this line searchForCharFrom = line.textStart() - startOfFragmentInBlock; // It's a new line. So we should look at the first tab-stop properties for the next \t. currentTabStop = 0; } else { // fragment starts in the middle of the line searchForCharFrom = 0; } if (line.textStart() + line.textLength() > startOfFragmentInBlock + currentFragment.length()) { // fragment ends before the end of line. need to see only till the end of the fragment. searchForCharTill = currentFragment.length(); } else { // line ends before the fragment ends. need to see only till the end of this line. // but then, we need to convert the end of line to an index into fragText searchForCharTill = line.textLength() + line.textStart() - startOfFragmentInBlock; } for (int i = searchForCharFrom ; i < searchForCharTill; i++) { if (currentTabStop >= tabList.size() && !showFormattingCharacters) // no more decorations break; if (fragText[i] == '\t') { qreal x1(0.0); qreal x2(0.0); if (showFormattingCharacters) { x1 = line.cursorToX(startOfFragmentInBlock + i); x2 = line.cursorToX(startOfFragmentInBlock + i + 1); qreal y = line.position().y() + line.ascent() - fm.xHeight()/2.0; qreal arrowDim = fm.xHeight()/2.0; QPen penBackup = painter->pen(); QPen pen = painter->pen(); pen.setWidthF(fm.ascent()/10.0); pen.setStyle(Qt::SolidLine); painter->setPen(pen); painter->drawLine(QPointF(x1, y), QPointF(x2, y)); painter->drawLine(QPointF(x2 - arrowDim, y - arrowDim), QPointF(x2, y)); painter->drawLine(QPointF(x2 - arrowDim, y + arrowDim), QPointF(x2, y)); painter->setPen(penBackup); } if (currentTabStop < tabList.size()) { // still tabsstops worth examining if (!showFormattingCharacters) { // only then was it not calculated x1 = line.cursorToX(startOfFragmentInBlock + i); } // find a tab-stop decoration for this tab position // for eg., if there's a tab-stop at 1in, but the text before \t already spans 1.2in, // we should look at the next tab-stop KoText::Tab tab; do { tab = qvariant_cast(tabList[currentTabStop]); currentTabStop++; // comparing with x1 should work for all of left/right/center/char tabs } while (tab.position <= x1 && currentTabStop < tabList.size()); if (tab.position > x1) { if (!showFormattingCharacters) { // only then was it not calculated x2 = line.cursorToX(startOfFragmentInBlock + i + 1); } qreal tabStyleLeftLineMargin = tabStyleLineMargin; qreal tabStyleRightLineMargin = tabStyleLineMargin; // no margin if its adjacent char is also a tab if (i > searchForCharFrom && fragText[i-1] == '\t') tabStyleLeftLineMargin = 0; if (i < (searchForCharTill - 1) && fragText[i+1] == '\t') tabStyleRightLineMargin = 0; qreal y = line.position().y() + line.ascent() - 1; x1 += tabStyleLeftLineMargin; x2 -= tabStyleRightLineMargin; QColor tabDecorColor = currentFragment.charFormat().foreground().color(); if (tab.leaderColor.isValid()) tabDecorColor = tab.leaderColor; qreal width = computeWidth(tab.leaderWeight, tab.leaderWidth, painter->font()); if (x1 < x2) { if (tab.leaderText.isEmpty()) { drawDecorationLine(painter, tabDecorColor, tab.leaderType, tab.leaderStyle, width, x1, x2, y); } else { drawDecorationText(painter, line, tabDecorColor, tab.leaderText, x1, x2); } } } } } else if (showFormattingCharacters) { if (fragText[i] == ' ' || fragText[i] == QChar::Nbsp) { qreal x = line.cursorToX(startOfFragmentInBlock + i); qreal y = line.position().y() + line.ascent(); painter->drawText(QPointF(x, y), QChar((ushort)0xb7)); } else if (fragText[i] == QChar::LineSeparator){ qreal x = line.cursorToX(startOfFragmentInBlock + i); qreal y = line.position().y() + line.ascent(); painter->drawText(QPointF(x, y), QChar((ushort)0x21B5)); } } } return currentTabStop; } diff --git a/plugins/flake/textshape/textlayout/KoTextLayoutCellHelper.h b/plugins/flake/textshape/textlayout/KoTextLayoutCellHelper.h index 3b344c8219..839ab3cf31 100644 --- a/plugins/flake/textshape/textlayout/KoTextLayoutCellHelper.h +++ b/plugins/flake/textshape/textlayout/KoTextLayoutCellHelper.h @@ -1,138 +1,140 @@ /* This file is part of the KDE project * Copyright (C) 2006-2010 Thomas Zander * Copyright (C) 2008 Thorsten Zachmann * Copyright (C) 2008 Roopesh Chander * Copyright (C) 2008 Girish Ramakrishnan * Copyright (C) 2009 KO GmbH * Copyright (C) 2011 Pierre Ducroquet * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOTEXTLAYOUTCELLHELPER_H #define KOTEXTLAYOUTCELLHELPER_H #include "kritatextlayout_export.h" #include #include class KoTableCellStyle; class QPainter; class KRITATEXTLAYOUT_EXPORT KoTextLayoutCellHelper : public QObject { Q_OBJECT public: explicit KoTextLayoutCellHelper(const KoTableCellStyle &cellStyle, QObject *parent = 0); /// draws a horizontal wave line void drawHorizontalWave(KoBorder::BorderStyle style, QPainter &painter, qreal x, qreal w, qreal t) const; /// draws a vertical wave line void drawVerticalWave(KoBorder::BorderStyle style, QPainter &painter, qreal y, qreal h, qreal t) const; /** * Paint the borders. * - * @painter the painter to draw with. - * @bounds the bounding rectangle to draw. - * @blanks a painterpath where blank borders should be added to. + * @param painter the painter to draw with. + * @param bounds the bounding rectangle to draw. + * @param blanks a painterpath where blank borders should be added to. */ void paintBorders(QPainter &painter, const QRectF &bounds, QVector *blanks) const; /** * Paint the diagonal borders. * - * @painter the painter to draw with. - * @bounds the bounding rectangle to draw. + * @param painter the painter to draw with. + * @param bounds the bounding rectangle to draw. */ void paintDiagonalBorders(QPainter &painter, const QRectF &bounds) const; /** * Paint the top border. * - * @painter the painter to draw with. - * @x the x position. - * @y the y position. - * @w the width. - * @blanks a painterpath where blank borders should be added to. + * @param painter the painter to draw with. + * @param x the x position. + * @param y the y position. + * @param w the width. + * @param blanks a painterpath where blank borders should be added to. */ void drawTopHorizontalBorder(QPainter &painter, qreal x, qreal y, qreal w, QVector *blanks = 0) const; /** * Paint the border that is shared. * It only draws the thickest and it always draws it below the y position. * - * @painter the painter to draw with. - * @x the x position. - * @y the y position. - * @w the width. - * @blanks a painterpath where blank borders should be added to. + * @param painter the painter to draw with. + * @param styleBelow the table cell style. + * @param x the x position. + * @param y the y position. + * @param w the width. + * @param blanks a painterpath where blank borders should be added to. */ void drawSharedHorizontalBorder(QPainter &painter, const KoTableCellStyle &styleBelow, qreal x, qreal y, qreal w, QVector *blanks = 0) const; /** * Paint the bottom border. * - * @painter the painter to draw with. - * @x the x position. - * @y the y position. - * @w the width. - * @blanks a painterpath where blank borders should be added to. + * @param painter the painter to draw with. + * @param x the x position. + * @param y the y position. + * @param w the width. + * @param blanks a painterpath where blank borders should be added to. */ void drawBottomHorizontalBorder(QPainter &painter, qreal x, qreal y, qreal w, QVector *blanks = 0) const; /** * Paint the leftmost border. * - * @painter the painter to draw with. - * @x the x position. - * @y the y position. - * @h the height. - * @blanks a painterpath where blank borders should be added to. + * @param painter the painter to draw with. + * @param x the x position. + * @param y the y position. + * @param h the height. + * @param blanks a painterpath where blank borders should be added to. */ void drawLeftmostVerticalBorder(QPainter &painter, qreal x, qreal y, qreal h, QVector *blanks = 0) const; /** * Paint the border that is shared. - * It only draws the thickest and it always draws it below the y position. + * It only draws the thickest and it always draws it to the right of the x position. * - * @painter the painter to draw with. - * @x the x position. - * @y the y position. - * @h the height. - * @blanks a painterpath where blank borders should be added to. + * @param painter the painter to draw with. + * @param styleRight the table cell style. + * @param x the x position. + * @param y the y position. + * @param h the height. + * @param blanks a painterpath where blank borders should be added to. */ void drawSharedVerticalBorder(QPainter &painter, const KoTableCellStyle &styleRight, qreal x, qreal y, qreal h, QVector *blanks = 0) const; /** * Paint the rightmost border. * - * @painter the painter to draw with. - * @x the x position. - * @y the y position. - * @h the height. - * @blanks a painterpath where blank borders should be added to. + * @param painter the painter to draw with. + * @param x the x position. + * @param y the y position. + * @param h the height. + * @param blanks a painterpath where blank borders should be added to. */ void drawRightmostVerticalBorder(QPainter &painter, qreal x, qreal y, qreal h, QVector *blanks = 0) const; private: const KoTableCellStyle &m_cellStyle; }; #endif // KOTEXTLAYOUTCELLHELPER_H diff --git a/plugins/flake/textshape/textlayout/KoTextShapeData.h b/plugins/flake/textshape/textlayout/KoTextShapeData.h index ffdbca958d..35edead9f5 100644 --- a/plugins/flake/textshape/textlayout/KoTextShapeData.h +++ b/plugins/flake/textshape/textlayout/KoTextShapeData.h @@ -1,147 +1,145 @@ /* This file is part of the KDE project * Copyright (C) 2006, 2009-2010 Thomas Zander * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOTEXTSHAPEDATA_H #define KOTEXTSHAPEDATA_H #include "KoText.h" #include "kritatextlayout_export.h" #include #include class QTextDocument; class KoShapeLoadingContext; class KoShapeSavingContext; class KoTextShapeDataPrivate; class KoDocumentRdfBase; class KoTextLayoutRootArea; /** * The data store that is held by each TextShape instance. * This is a separate object to allow Words proper to use this class' API and * access the internals of the text shape. * * This class holds a QTextDocument pointer and is built so multiple shapes (and thus * multiple instances of this shape data) can share one QTextDocument by providing a * different view on (a different part of) the QTextDocument. */ class KRITATEXTLAYOUT_EXPORT KoTextShapeData : public KoTextShapeDataBase { Q_OBJECT public: /// constructor KoTextShapeData(); ~KoTextShapeData() override; KoShapeUserData* clone() const override; /** * Replace the QTextDocument this shape will render. * @param document the new document. If there was an old document owned, it will be deleted. - * @param transferOwnership if true then the document will be considered the responsibility - * of this data and the doc will be deleted when this shapeData dies. */ void setDocument(QTextDocument *document); /** * return the amount of points into the document (y) this shape will display. */ qreal documentOffset() const; /// mark shape as dirty triggering a re-layout of its text. void setDirty(); /// return if the shape is marked dirty and its text content needs to be relayout bool isDirty() const; /// Set the rootArea that is associated to the textshape void setRootArea(KoTextLayoutRootArea *rootArea); /// the rootArea that is associated to the textshape KoTextLayoutRootArea *rootArea(); void setLeftPadding(qreal padding); qreal leftPadding() const; void setTopPadding(qreal padding); qreal topPadding() const; void setRightPadding(qreal padding); qreal rightPadding() const; void setBottomPadding(qreal padding); qreal bottomPadding() const; void setPadding(qreal padding); /** * Load the TextShape from ODF. * * @see the @a TextShape::loadOdf() method which calls this method. * @see the @a KoTextLoader::loadBody() method which got called by this method * to load the ODF. */ bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context, KoDocumentRdfBase *rdfData, KoShape *shape = 0); /** * Load the TextShape from ODF. * Overloaded method provided for your convenience. */ bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override { return loadOdf(element, context, 0); } /** * Store the TextShape data as ODF. * @see TextShape::saveOdf() */ void saveOdf(KoShapeSavingContext &context, KoDocumentRdfBase *rdfData, int from = 0, int to = -1) const; /** * Store the TextShape data as ODF. * Overloaded method provided for your convenience. */ void saveOdf(KoShapeSavingContext &context, int from = 0, int to = -1) const override { saveOdf(context, 0, from, to); } // reimplemented void loadStyle(const KoXmlElement &element, KoShapeLoadingContext &context) override; // reimplemented void saveStyle(KoGenStyle &style, KoShapeSavingContext &context) const override; /** * Set the page direction. * The page direction will determine behavior on the insertion of new text and those * new paragraphs default direction. */ void setPageDirection(KoText::Direction direction); /** * Return the direction set on the page. * The page direction will determine behavior on the insertion of new text and those * new paragraphs default direction. */ KoText::Direction pageDirection() const; private: KoTextShapeData(KoTextShapeDataPrivate *dd); private: Q_DECLARE_PRIVATE(KoTextShapeData) }; #endif diff --git a/plugins/impex/exr/krita_exr.desktop b/plugins/impex/exr/krita_exr.desktop index ed2565b3eb..c21e965c6b 100644 --- a/plugins/impex/exr/krita_exr.desktop +++ b/plugins/impex/exr/krita_exr.desktop @@ -1,124 +1,124 @@ [Desktop Entry] Categories=Qt;KDE;Office;Graphics; Exec=krita %F GenericName=Application for Drawing and Handling of Images GenericName[ar]=تطبيق لرسم الصور والتعامل معها GenericName[bg]=Приложение за рисуване и обработка на изображения GenericName[bs]=Aplikacija za crtanje i upravljanje slikom GenericName[ca]=Aplicació per a dibuix i modificació d'imatges GenericName[ca@valencia]=Aplicació per a dibuix i modificació d'imatges GenericName[da]=Tegne- og billedbehandlingsprogram GenericName[de]=Programm zum Zeichnen und Bearbeiten von Bildern GenericName[el]=Εφαρμογή για επεξεργασία και χειρισμό εικόνων GenericName[en_GB]=Application for Drawing and Handling of Images GenericName[eo]=Aplikaĵo por Desegnado kaj Mastrumado de Bildoj GenericName[es]=Aplicación para dibujo y manipulación de imágenes GenericName[et]=Joonistamise ja pilditöötluse rakendus GenericName[eu]=Irudiak marrazteko eta manipulatzeko aplikazioa GenericName[fa]=کاربرد برای ترسیم و به کار بردن تصاویر GenericName[fi]=Ohjelma kuvien piirtämiseen ja käsittelyyn GenericName[fr]=Application pour dessiner et manipuler des images GenericName[fy]=Aplikaasje om ôfbyldings mei te tekenjen en te bewurkjen GenericName[ga]=Feidhmchlár le haghaidh Líníochta agus Láimhseála Íomhánna GenericName[gl]=Aplicativo de debuxo e edición de imaxes GenericName[he]=יישום לצביעה וניהול תמונות GenericName[hi]=छवियों को ड्रा करने तथा उन्हें प्रबन्धित करने का अनुप्रयोग GenericName[hne]=फोटू मन ल ड्रा करे अउ ओ मन ल प्रबन्धित करे के अनुपरयोग GenericName[hu]=Rajzoló és képkezelő GenericName[is]=Teikni og myndvinnsluforrit GenericName[it]=Applicazione di disegno e gestione di immagini GenericName[ja]=描画と画像操作のためのアプリケーション GenericName[kk]=Кескінді салу және өңдеу бағдарламасы GenericName[ko]=그림 그리기 및 처리 프로그램 GenericName[lv]=Programma zīmēšanai un attēlu apstrādei GenericName[nb]=Program for tegning og bildehåndtering GenericName[nds]=Programm för't Teken un Bildhanteren GenericName[ne]=रेखाचित्र बनाउन र छविको ह्यान्डल गर्नका लागि अनुप्रयोग GenericName[nl]=Toepassing om afbeeldingen te tekenen en te bewerken GenericName[pl]=Program do rysowania i obróbki obrazów GenericName[pt]=Aplicação de Desenho e Manipulação de Imagens GenericName[pt_BR]=Aplicativo de desenho e manipulação de imagens GenericName[ru]=Приложение для рисования и редактирования изображений GenericName[sk]=Aplikácia na kresnenie a manilupáciu s obrázkami GenericName[sl]=Program za risanje in rokovanje s slikami GenericName[sv]=Program för att rita och hantera bilder GenericName[ta]=பிம்பங்களை கையாளுதல் மற்றும் வரைதலுக்கான பயன்னாடு GenericName[tr]=Çizim ve Resim İşleme Uygulaması GenericName[uk]=Програма для малювання і обробки зображень GenericName[uz]=Rasm chizish dasturi GenericName[uz@cyrillic]=Расм чизиш дастури GenericName[wa]=Programe po dessiner et apougnî des imådjes GenericName[x-test]=xxApplication for Drawing and Handling of Imagesxx -GenericName[zh_CN]=绘制和处理图像的应用程序 +GenericName[zh_CN]=用于绘制和处理图像的应用程序 GenericName[zh_TW]=繪圖與影像處理的應用程式 Icon=calligrakrita MimeType=image/exr; Name=Krita Name[af]=Krita Name[ar]=كريتا Name[bg]=Krita Name[br]=Krita Name[bs]=Krita Name[ca]=Krita Name[ca@valencia]=Krita Name[cs]=Krita Name[cy]=Krita Name[da]=Krita Name[de]=Krita Name[el]=Krita Name[en_GB]=Krita Name[eo]=Krita Name[es]=Krita Name[et]=Krita Name[eu]=Krita Name[fi]=Krita Name[fr]=Krita Name[fy]=Krita Name[ga]=Krita Name[gl]=Krita Name[he]=Krita Name[hi]=केरिता Name[hne]=केरिता Name[hr]=Krita Name[hu]=Krita Name[ia]=Krita Name[is]=Krita Name[it]=Krita Name[ja]=Krita Name[kk]=Krita Name[ko]=Krita Name[lt]=Krita Name[lv]=Krita Name[mr]=क्रिटा Name[ms]=Krita Name[nb]=Krita Name[nds]=Krita Name[ne]=क्रिता Name[nl]=Krita Name[pl]=Krita Name[pt]=Krita Name[pt_BR]=Krita Name[ro]=Krita Name[ru]=Krita Name[se]=Krita Name[sk]=Krita Name[sl]=Krita Name[sv]=Krita Name[ta]=கிரிட்டா Name[tg]=Krita Name[tr]=Krita Name[ug]=Krita Name[uk]=Krita Name[uz]=Krita Name[uz@cyrillic]=Krita Name[wa]=Krita Name[xh]=Krita Name[x-test]=xxKritaxx Name[zh_CN]=Krita Name[zh_TW]=Krita StartupNotify=true Terminal=false Type=Application X-KDE-SubstituteUID=false X-KDE-Username= NoDisplay=true diff --git a/plugins/impex/heif/krita_heif.desktop b/plugins/impex/heif/krita_heif.desktop index 6da0d4b9e4..52b988375b 100644 --- a/plugins/impex/heif/krita_heif.desktop +++ b/plugins/impex/heif/krita_heif.desktop @@ -1,124 +1,124 @@ [Desktop Entry] Categories=Qt;KDE;Office;Graphics; Exec=krita %F GenericName=Application for Drawing and Handling of Images GenericName[ar]=تطبيق لرسم الصور والتعامل معها GenericName[bg]=Приложение за рисуване и обработка на изображения GenericName[bs]=Aplikacija za crtanje i upravljanje slikom GenericName[ca]=Aplicació per a dibuix i modificació d'imatges GenericName[ca@valencia]=Aplicació per a dibuix i modificació d'imatges GenericName[da]=Tegne- og billedbehandlingsprogram GenericName[de]=Programm zum Zeichnen und Bearbeiten von Bildern GenericName[el]=Εφαρμογή για επεξεργασία και χειρισμό εικόνων GenericName[en_GB]=Application for Drawing and Handling of Images GenericName[eo]=Aplikaĵo por Desegnado kaj Mastrumado de Bildoj GenericName[es]=Aplicación para dibujo y manipulación de imágenes GenericName[et]=Joonistamise ja pilditöötluse rakendus GenericName[eu]=Irudiak marrazteko eta manipulatzeko aplikazioa GenericName[fa]=کاربرد برای ترسیم و به کار بردن تصاویر GenericName[fi]=Ohjelma kuvien piirtämiseen ja käsittelyyn GenericName[fr]=Application pour dessiner et manipuler des images GenericName[fy]=Aplikaasje om ôfbyldings mei te tekenjen en te bewurkjen GenericName[ga]=Feidhmchlár le haghaidh Líníochta agus Láimhseála Íomhánna GenericName[gl]=Aplicativo de debuxo e edición de imaxes GenericName[he]=יישום לצביעה וניהול תמונות GenericName[hi]=छवियों को ड्रा करने तथा उन्हें प्रबन्धित करने का अनुप्रयोग GenericName[hne]=फोटू मन ल ड्रा करे अउ ओ मन ल प्रबन्धित करे के अनुपरयोग GenericName[hu]=Rajzoló és képkezelő GenericName[is]=Teikni og myndvinnsluforrit GenericName[it]=Applicazione di disegno e gestione di immagini GenericName[ja]=描画と画像操作のためのアプリケーション GenericName[kk]=Кескінді салу және өңдеу бағдарламасы GenericName[ko]=그림 그리기 및 처리 프로그램 GenericName[lv]=Programma zīmēšanai un attēlu apstrādei GenericName[nb]=Program for tegning og bildehåndtering GenericName[nds]=Programm för't Teken un Bildhanteren GenericName[ne]=रेखाचित्र बनाउन र छविको ह्यान्डल गर्नका लागि अनुप्रयोग GenericName[nl]=Toepassing om afbeeldingen te tekenen en te bewerken GenericName[pl]=Program do rysowania i obróbki obrazów GenericName[pt]=Aplicação de Desenho e Manipulação de Imagens GenericName[pt_BR]=Aplicativo de desenho e manipulação de imagens GenericName[ru]=Приложение для рисования и редактирования изображений GenericName[sk]=Aplikácia na kresnenie a manilupáciu s obrázkami GenericName[sl]=Program za risanje in rokovanje s slikami GenericName[sv]=Program för att rita och hantera bilder GenericName[ta]=பிம்பங்களை கையாளுதல் மற்றும் வரைதலுக்கான பயன்னாடு GenericName[tr]=Çizim ve Resim İşleme Uygulaması GenericName[uk]=Програма для малювання і обробки зображень GenericName[uz]=Rasm chizish dasturi GenericName[uz@cyrillic]=Расм чизиш дастури GenericName[wa]=Programe po dessiner et apougnî des imådjes GenericName[x-test]=xxApplication for Drawing and Handling of Imagesxx -GenericName[zh_CN]=绘制和处理图像的应用程序 +GenericName[zh_CN]=用于绘制和处理图像的应用程序 GenericName[zh_TW]=繪圖與影像處理的應用程式 Icon=calligrakrita MimeType=image/heic; Name=Krita Name[af]=Krita Name[ar]=كريتا Name[bg]=Krita Name[br]=Krita Name[bs]=Krita Name[ca]=Krita Name[ca@valencia]=Krita Name[cs]=Krita Name[cy]=Krita Name[da]=Krita Name[de]=Krita Name[el]=Krita Name[en_GB]=Krita Name[eo]=Krita Name[es]=Krita Name[et]=Krita Name[eu]=Krita Name[fi]=Krita Name[fr]=Krita Name[fy]=Krita Name[ga]=Krita Name[gl]=Krita Name[he]=Krita Name[hi]=केरिता Name[hne]=केरिता Name[hr]=Krita Name[hu]=Krita Name[ia]=Krita Name[is]=Krita Name[it]=Krita Name[ja]=Krita Name[kk]=Krita Name[ko]=Krita Name[lt]=Krita Name[lv]=Krita Name[mr]=क्रिटा Name[ms]=Krita Name[nb]=Krita Name[nds]=Krita Name[ne]=क्रिता Name[nl]=Krita Name[pl]=Krita Name[pt]=Krita Name[pt_BR]=Krita Name[ro]=Krita Name[ru]=Krita Name[se]=Krita Name[sk]=Krita Name[sl]=Krita Name[sv]=Krita Name[ta]=கிரிட்டா Name[tg]=Krita Name[tr]=Krita Name[ug]=Krita Name[uk]=Krita Name[uz]=Krita Name[uz@cyrillic]=Krita Name[wa]=Krita Name[xh]=Krita Name[x-test]=xxKritaxx Name[zh_CN]=Krita Name[zh_TW]=Krita StartupNotify=true Terminal=false Type=Application X-KDE-SubstituteUID=false X-KDE-Username= NoDisplay=true diff --git a/plugins/paintops/libpaintop/kis_color_source.h b/plugins/paintops/libpaintop/kis_color_source.h index 4944c30600..9db82b491a 100644 --- a/plugins/paintops/libpaintop/kis_color_source.h +++ b/plugins/paintops/libpaintop/kis_color_source.h @@ -1,151 +1,152 @@ /* * Copyright (c) 2006-2007, 2009 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _KIS_DYNAMIC_COLORING_H_ #define _KIS_DYNAMIC_COLORING_H_ #include "kis_paintop_option.h" #include #include #include #include #include class KoColorTransformation; class KisPaintInformation; /** * A color source allow to abstract how a brush is colorized, * and to apply transformation. * * The first function to call is @ref selectColor , then any of the transformation. */ class PAINTOP_EXPORT KisColorSource { public: virtual ~KisColorSource(); public: /** * This is function is called to initialize the color that will be used for the dab. * @param mix is a parameter between 0.0 and 1.0 + * @param pi paint information */ virtual void selectColor(double mix, const KisPaintInformation &pi) = 0; /** * Apply a color transformation on the selected color */ virtual void applyColorTransformation(const KoColorTransformation* transfo) = 0; virtual const KoColorSpace* colorSpace() const = 0; /** * Apply the color on a paint device */ virtual void colorize(KisPaintDeviceSP, const QRect& rect, const QPoint& _offset) const = 0; /** * @return true if the color is an uniform color */ virtual bool isUniformColor() const = 0; /** * @return the color if the color is uniformed */ virtual const KoColor& uniformColor() const; }; class PAINTOP_EXPORT KisUniformColorSource : public KisColorSource { public: KisUniformColorSource(); ~KisUniformColorSource() override; virtual void rotate(double); virtual void resize(double , double); void applyColorTransformation(const KoColorTransformation* transfo) override; const KoColorSpace* colorSpace() const override; void colorize(KisPaintDeviceSP, const QRect& rect, const QPoint& offset) const override; bool isUniformColor() const override; const KoColor& uniformColor() const override; protected: KoColor m_color; }; class PAINTOP_EXPORT KisPlainColorSource : public KisUniformColorSource { public: KisPlainColorSource(const KoColor& backGroundColor, const KoColor& foreGroundColor); ~KisPlainColorSource() override; void selectColor(double mix, const KisPaintInformation &pi) override; private: KoColor m_backGroundColor; KoColor m_cachedBackGroundColor; KoColor m_foreGroundColor; }; class PAINTOP_EXPORT KisGradientColorSource : public KisUniformColorSource { public: KisGradientColorSource(const KoAbstractGradientSP gradient, const KoColorSpace* workingCS); ~KisGradientColorSource() override; void selectColor(double mix, const KisPaintInformation &pi) override; private: const KoAbstractGradientSP m_gradient; }; class PAINTOP_EXPORT KisUniformRandomColorSource : public KisUniformColorSource { public: KisUniformRandomColorSource(); ~KisUniformRandomColorSource() override; void selectColor(double mix, const KisPaintInformation &pi) override; }; class PAINTOP_EXPORT KisTotalRandomColorSource : public KisColorSource { public: KisTotalRandomColorSource(); ~KisTotalRandomColorSource() override; public: void selectColor(double mix, const KisPaintInformation &pi) override; void applyColorTransformation(const KoColorTransformation* transfo) override; const KoColorSpace* colorSpace() const override; void colorize(KisPaintDeviceSP, const QRect& rect, const QPoint& offset) const override; virtual void rotate(double r); virtual void resize(double xs, double ys); bool isUniformColor() const override; private: const KoColorSpace* m_colorSpace; }; class PAINTOP_EXPORT KoPatternColorSource : public KisColorSource { public: KoPatternColorSource(KisPaintDeviceSP _pattern, int _width, int _height, bool _locked); ~KoPatternColorSource() override; public: void selectColor(double mix, const KisPaintInformation &pi) override; void applyColorTransformation(const KoColorTransformation* transfo) override; const KoColorSpace* colorSpace() const override; void colorize(KisPaintDeviceSP, const QRect& rect, const QPoint& _offset) const override; virtual void rotate(double r); virtual void resize(double xs, double ys); bool isUniformColor() const override; private: const KisPaintDeviceSP m_device; QRect m_bounds; bool m_locked; }; #endif diff --git a/plugins/paintops/libpaintop/kis_dab_cache_base.h b/plugins/paintops/libpaintop/kis_dab_cache_base.h index 3dff16df20..3c0d6bc0ba 100644 --- a/plugins/paintops/libpaintop/kis_dab_cache_base.h +++ b/plugins/paintops/libpaintop/kis_dab_cache_base.h @@ -1,128 +1,123 @@ /* * Copyright (c) 2012 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 __KIS_DAB_CACHE_BASE_H #define __KIS_DAB_CACHE_BASE_H #include "kritapaintop_export.h" #include "kis_brush.h" #include "KisDabCacheUtils.h" class KisColorSource; class KisPressureSharpnessOption; class KisTextureProperties; class KisPressureMirrorOption; class KisPrecisionOption; struct MirrorProperties; /** * @brief The KisDabCacheBase class provides caching for dabs into the brush paintop * * This class adds caching of the dabs to the paintop system of Krita. * Such cache makes the execution of the benchmarks up to 2 times faster. * Subjectively, the real painting becomes much faster, especially with * huge brushes. Artists report up to 20% speed gain while painting. * * Of course, such caching makes the painting a bit less precise: we need * to tolerate subpixel differences to allow the cache to work. Sometimes * small difference in the size of a dab can also be acceptable. That is * why I introduced levels of precision. They are graded from 1 to 5: from * the fastest and less precise to the slowest, but with the best quality. * You can see the slider in the paintop settings dialog. The ToolTip text * explains which features of the brush are sacrificed on each precision * level. * * The texturing and mirroring problems are solved. */ class PAINTOP_EXPORT KisDabCacheBase { public: KisDabCacheBase(); ~KisDabCacheBase(); void setMirrorPostprocessing(KisPressureMirrorOption *option); void setPrecisionOption(KisPrecisionOption *option); /** * Disables handling of the subPixelX and subPixelY values, this * is needed at least for the Color Smudge paint op, which reads * aligned areas from image, so additional offsets generated by * the subpixel precision should be avoided */ void disableSubpixelPrecision(); /** * Return true if the dab needs postprocessing by special options * like 'texture' or 'sharpness' */ bool needSeparateOriginal(KisTextureProperties *textureOption, KisPressureSharpnessOption *sharpnessOption) const; protected: /** * Fetches all the necessary information for dab generation and * tells if the caller must should reuse the preciously returned dab. * * Please note that KisDabCacheBase has an internal state, that keeps the * parameters of the previously generated (on a cache-miss) dab. This function * automatically updates this state when 'shouldUseCache == false'. Therefore, the * caller *must* generate the dab if and only if when 'shouldUseCache == false'. * Otherwise the internal state will become inconsistent. * * @param hasDabInCache shows if the caller has something in its cache * @param resources rendering resources available for this dab - * @param color current painting color - * @param cursorPoint cursor point at which the dab should be painted - * @param shape dab shape requested by the caller. It will be modified before - * generation to accommodate the mirroring and rotation options. - * @param info painting info associated with the dab - * @param softnessFactor softness factor + * @param request the request information * @param di (OUT) calculated dab generation information * @param shouldUseCache (OUT) shows whether the caller *must* use cache or not */ void fetchDabGenerationInfo(bool hasDabInCache, KisDabCacheUtils::DabRenderingResources *resources, const KisDabCacheUtils::DabRequestInfo &request, /* out */ KisDabCacheUtils::DabGenerationInfo *di, bool *shouldUseCache); private: struct SavedDabParameters; struct DabPosition; private: inline SavedDabParameters getDabParameters(KisBrushSP brush, const KoColor& color, KisDabShape const&, const KisPaintInformation& info, double subPixelX, double subPixelY, qreal softnessFactor, MirrorProperties mirrorProperties); inline KisDabCacheBase::DabPosition calculateDabRect(KisBrushSP brush, const QPointF &cursorPoint, KisDabShape, const KisPaintInformation& info, const MirrorProperties &mirrorProperties, KisPressureSharpnessOption *sharpnessOption); private: struct Private; Private * const m_d; }; #endif /* __KIS_DAB_CACHE_BASE_H */ diff --git a/plugins/paintops/libpaintop/kis_dynamic_sensor.h b/plugins/paintops/libpaintop/kis_dynamic_sensor.h index 80a31bce4c..a4b843c36f 100644 --- a/plugins/paintops/libpaintop/kis_dynamic_sensor.h +++ b/plugins/paintops/libpaintop/kis_dynamic_sensor.h @@ -1,220 +1,221 @@ /* * Copyright (c) 2006 Cyrille Berger * Copyright (c) 2011 Lukáš Tvrdý * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _KIS_DYNAMIC_SENSOR_H_ #define _KIS_DYNAMIC_SENSOR_H_ #include #include #include #include #include "kis_serializable_configuration.h" #include "kis_curve_label.h" #include #include #include class QWidget; class KisPaintInformation; const KoID FuzzyPerDabId("fuzzy", ki18n("Fuzzy Dab")); ///< generate a random number const KoID FuzzyPerStrokeId("fuzzystroke", ki18n("Fuzzy Stroke")); ///< generate a random number const KoID SpeedId("speed", ki18n("Speed")); ///< generate a number depending on the speed of the cursor const KoID FadeId("fade", ki18n("Fade")); ///< generate a number that increase every time you call it (e.g. per dab) const KoID DistanceId("distance", ki18n("Distance")); ///< generate a number that increase with distance const KoID TimeId("time", ki18n("Time")); ///< generate a number that increase with time const KoID DrawingAngleId("drawingangle", ki18n("Drawing angle")); ///< number depending on the angle const KoID RotationId("rotation", ki18n("Rotation")); ///< rotation coming from the device const KoID PressureId("pressure", ki18n("Pressure")); ///< number depending on the pressure const KoID PressureInId("pressurein", ki18n("PressureIn")); ///< number depending on the pressure const KoID XTiltId("xtilt", ki18n("X-Tilt")); ///< number depending on X-tilt const KoID YTiltId("ytilt", ki18n("Y-Tilt")); ///< number depending on Y-tilt /** * "TiltDirection" and "TiltElevation" parameters are written to * preset files as "ascension" and "declination" to keep backward * compatibility with older presets from the days when they were called * differently. */ const KoID TiltDirectionId("ascension", ki18n("Tilt direction")); /// < number depending on the X and Y tilt, tilt direction is 0 when stylus nib points to you and changes clockwise from -180 to +180. const KoID TiltElevationId("declination", ki18n("Tilt elevation")); /// < tilt elevation is 90 when stylus is perpendicular to tablet and 0 when it's parallel to tablet const KoID PerspectiveId("perspective", ki18n("Perspective")); ///< number depending on the distance on the perspective grid const KoID TangentialPressureId("tangentialpressure", ki18n("Tangential pressure")); ///< the wheel on an airbrush device const KoID SensorsListId("sensorslist", "SHOULD NOT APPEAR IN THE UI !"); ///< this a non user-visible sensor that can store a list of other sensors, and multiply their output class KisDynamicSensor; typedef KisSharedPtr KisDynamicSensorSP; enum DynamicSensorType { FUZZY_PER_DAB, FUZZY_PER_STROKE, SPEED, FADE, DISTANCE, TIME, ANGLE, ROTATION, PRESSURE, XTILT, YTILT, TILT_DIRECTION, TILT_ELEVATATION, PERSPECTIVE, TANGENTIAL_PRESSURE, SENSORS_LIST, PRESSURE_IN, UNKNOWN = 255 }; /** * Sensors are used to extract from KisPaintInformation a single * double value which can be used to control the parameters of * a brush. */ class PAINTOP_EXPORT KisDynamicSensor : public KisSerializableConfiguration { public: enum ParameterSign { NegativeParameter = -1, UnSignedParameter = 0, PositiveParameter = 1 }; protected: KisDynamicSensor(DynamicSensorType type); public: ~KisDynamicSensor() override; /** * @return the value of this sensor for the given KisPaintInformation */ qreal parameter(const KisPaintInformation& info); /** * This function is call before beginning a stroke to reset the sensor. * Default implementation does nothing. */ virtual void reset(); /** + * @param parent the parent QWidget * @param selector is a \ref QWidget that contains a signal called "parametersChanged()" */ virtual QWidget* createConfigurationWidget(QWidget* parent, QWidget* selector); /** * Creates a sensor from its identifier. */ static KisDynamicSensorSP id2Sensor(const KoID& id, const QString &parentOptionName); static KisDynamicSensorSP id2Sensor(const QString& s, const QString &parentOptionName) { return id2Sensor(KoID(s), parentOptionName); } static DynamicSensorType id2Type(const KoID& id); static DynamicSensorType id2Type(const QString& s) { return id2Type(KoID(s)); } /** * type2Sensor creates a new sensor for the give type */ static KisDynamicSensorSP type2Sensor(DynamicSensorType sensorType, const QString &parentOptionName); static QString minimumLabel(DynamicSensorType sensorType); static QString maximumLabel(DynamicSensorType sensorType, int max = -1); static int minimumValue(DynamicSensorType sensorType); static int maximumValue(DynamicSensorType sensorType, int max = -1); static QString valueSuffix(DynamicSensorType sensorType); static KisDynamicSensorSP createFromXML(const QString&, const QString &parentOptionName); static KisDynamicSensorSP createFromXML(const QDomElement&, const QString &parentOptionName); /** * @return the list of sensors */ static QList sensorsIds(); static QList sensorsTypes(); /** * @return the identifier of this sensor */ static QString id(DynamicSensorType sensorType); using KisSerializableConfiguration::fromXML; using KisSerializableConfiguration::toXML; void toXML(QDomDocument&, QDomElement&) const override; void fromXML(const QDomElement&) override; void setCurve(const KisCubicCurve& curve); const KisCubicCurve& curve() const; void removeCurve(); bool hasCustomCurve() const; void setActive(bool active); bool isActive() const; virtual bool dependsOnCanvasRotation() const; virtual bool isAdditive() const; virtual bool isAbsoluteRotation() const; inline DynamicSensorType sensorType() const { return m_type; } /** * @return the currently set length or -1 if not relevant */ int length() { return m_length; } public: static inline qreal scalingToAdditive(qreal x) { return -1.0 + 2.0 * x; } static inline qreal additiveToScaling(qreal x) { return 0.5 * (1.0 + x); } protected: virtual qreal value(const KisPaintInformation& info) = 0; int m_length; private: Q_DISABLE_COPY(KisDynamicSensor) DynamicSensorType m_type; bool m_customCurve; KisCubicCurve m_curve; bool m_active; }; #endif diff --git a/plugins/paintops/libpaintop/kis_paintop_plugin_utils.h b/plugins/paintops/libpaintop/kis_paintop_plugin_utils.h index 2a8b0e839d..a251d987ed 100644 --- a/plugins/paintops/libpaintop/kis_paintop_plugin_utils.h +++ b/plugins/paintops/libpaintop/kis_paintop_plugin_utils.h @@ -1,101 +1,114 @@ /* * Copyright (c) 2014 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the 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 __KIS_PAINTOP_PLUGIN_UTILS_H #define __KIS_PAINTOP_PLUGIN_UTILS_H #include "kis_paint_information.h" #include "kis_paintop_utils.h" #include "kis_paintop_settings.h" #include "kis_airbrush_option_widget.h" #include "kis_pressure_spacing_option.h" #include "kis_pressure_rate_option.h" namespace KisPaintOpPluginUtils { /** * Similar to KisPaintOpUtils::effectiveSpacing, but some of the required parameters are obtained * from the provided configuration options. This function assumes a common configuration where * spacing and airbrush settings are configured through a KisPressureSpacingOption and * KisAirbrushOption. This type of configuration is used by several different paintops. + * @param dabWidth - The dab width. + * @param dabHeight - The dab height. + * @param isotropicSpacing - If @c true the spacing should be isotropic. + * @param rotation - The rotation angle in radians. + * @param axesFlipped - If @c true the axes should be flipped. + * @param spacingVal - The spacing value. + * @param autoSpacingActive - If @c true the autospacing will be activated. + * @param autoSpacingCoeff - The autospacing coefficient. + * @param lodScale - The level of details scale. * @param airbrushOption - The airbrushing option. Can be null for paintops that don't support * airbrushing. * @param spacingOption - The pressure-curve spacing option. Can be null for paintops that don't * support pressure-based spacing. + * @param pi - The paint information. + * @see KisPaintInformation */ KisSpacingInformation effectiveSpacing(qreal dabWidth, qreal dabHeight, bool isotropicSpacing, qreal rotation, bool axesFlipped, qreal spacingVal, bool autoSpacingActive, qreal autoSpacingCoeff, qreal lodScale, const KisAirbrushOptionProperties *airbrushOption, const KisPressureSpacingOption *spacingOption, const KisPaintInformation &pi) { // Extract required parameters. bool distanceSpacingEnabled = true; if (airbrushOption && airbrushOption->enabled) { distanceSpacingEnabled = !airbrushOption->ignoreSpacing; } qreal extraScale = 1.0; if (spacingOption && spacingOption->isChecked()) { extraScale = spacingOption->apply(pi); } return KisPaintOpUtils::effectiveSpacing(dabWidth, dabHeight, extraScale, distanceSpacingEnabled, isotropicSpacing, rotation, axesFlipped, spacingVal, autoSpacingActive, autoSpacingCoeff, lodScale); } /** * Similar to KisPaintOpUtils::effectiveTiming, but some of the required parameters are obtained * from the provided configuration options. This function assumes a common configuration where * airbrush settings are configured through a KisAirbrushOption and KisPressureRateOption. This type * of configuration is used by several different paintops. * @param airbrushOption - The airbrushing option. Can be null for paintops that don't support * airbrushing. * @param rateOption - The pressure-curve airbrush rate option. Can be null for paintops that don't * support a pressure-based airbrush rate. + * @param pi - The paint information. + * @see KisPaintInformation */ KisTimingInformation effectiveTiming(const KisAirbrushOptionProperties *airbrushOption, const KisPressureRateOption *rateOption, const KisPaintInformation &pi) { // Extract required parameters. bool timingEnabled = false; qreal timingInterval = LONG_TIME; if (airbrushOption) { timingEnabled = airbrushOption->enabled; timingInterval = airbrushOption->airbrushInterval; } qreal rateExtraScale = 1.0; if (rateOption && rateOption->isChecked()) { rateExtraScale = rateOption->apply(pi); } return KisPaintOpUtils::effectiveTiming(timingEnabled, timingInterval, rateExtraScale); } } #endif /* __KIS_PAINTOP_PLUGIN_UTILS_H */ diff --git a/plugins/paintops/libpaintop/kis_texture_option.h b/plugins/paintops/libpaintop/kis_texture_option.h index 1d22b6c271..0df28f2510 100644 --- a/plugins/paintops/libpaintop/kis_texture_option.h +++ b/plugins/paintops/libpaintop/kis_texture_option.h @@ -1,97 +1,98 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2012 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KIS_TEXTURE_OPTION_H #define KIS_TEXTURE_OPTION_H #include #include #include #include "kis_paintop_option.h" #include "kis_pressure_texture_strength_option.h" #include "KisTextureMaskInfo.h" #include class KisTextureChooser; class KoPattern; class KoResource; class KisPropertiesConfiguration; class KisPaintopLodLimitations; class PAINTOP_EXPORT KisTextureOption : public KisPaintOpOption { Q_OBJECT public: explicit KisTextureOption(); ~KisTextureOption() override; public Q_SLOTS: void writeOptionSetting(KisPropertiesConfigurationSP setting) const override; void readOptionSetting(const KisPropertiesConfigurationSP setting) override; void lodLimitations(KisPaintopLodLimitations *l) const override; private Q_SLOTS: void resetGUI(KoResourceSP ); /// called when a new pattern is selected private: /// UI Widget that stores all the texture options KisTextureChooser* m_textureOptions; }; class PAINTOP_EXPORT KisTextureProperties { public: KisTextureProperties(int levelOfDetail); enum TexturingMode { MULTIPLY, SUBTRACT }; bool m_enabled; /** * @brief apply combine the texture map with the dab * @param dab the colored, final representation of the dab, after mirroring and everything. * @param offset the position of the dab on the image. used to calculate the position of the mask pattern + * @param info the paint information */ void apply(KisFixedPaintDeviceSP dab, const QPoint& offset, const KisPaintInformation & info); void fillProperties(const KisPropertiesConfigurationSP setting); private: int m_offsetX; int m_offsetY; TexturingMode m_texturingMode; int m_levelOfDetail; private: KisPressureTextureStrengthOption m_strengthOption; KisTextureMaskInfoSP m_maskInfo; }; #endif // KIS_TEXTURE_OPTION_H diff --git a/plugins/python/assignprofiledialog/kritapykrita_assignprofiledialog.desktop b/plugins/python/assignprofiledialog/kritapykrita_assignprofiledialog.desktop index e476b542f3..0e54ca976d 100644 --- a/plugins/python/assignprofiledialog/kritapykrita_assignprofiledialog.desktop +++ b/plugins/python/assignprofiledialog/kritapykrita_assignprofiledialog.desktop @@ -1,51 +1,53 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=assignprofiledialog X-Python-2-Compatible=true X-Krita-Manual=Manual.html Name=Assign Profile to Image Name[ar]=إسناد اللاحات إلى الصور Name[ca]=Assigna un perfil a una imatge Name[ca@valencia]=Assigna un perfil a una imatge Name[cs]=Přiřadit obrázku profil Name[el]=Αντιστοίχιση προφίλ σε εικόνα Name[en_GB]=Assign Profile to Image Name[es]=Asignar perfil a imagen Name[eu]=Esleitu profila irudiari +Name[fi]=Liitä kuvaan profiili Name[fr]=Attribuer un profil à l'image Name[gl]=Asignar un perfil á imaxe Name[is]=Úthluta litasniði á myndina Name[it]=Assegna profilo a immagine Name[nl]=Profiel aan afbeelding toewijzen Name[pl]=Przypisz profil do obrazu Name[pt]=Atribuir um Perfil à Imagem Name[pt_BR]=Atribuir perfil a imagem Name[sv]=Tilldela profil till bild Name[tr]=Görüntüye Profil Ata Name[uk]=Призначити профіль до зображення Name[x-test]=xxAssign Profile to Imagexx Name[zh_CN]=为图像指定色彩配置文件 Name[zh_TW]=指定設定檔到圖像 Comment=Assign a profile to an image without converting it. Comment[ar]=أسنِد لاحة إلى صورة دون تحويلها. Comment[ca]=Assigna un perfil a una imatge sense convertir-la. Comment[ca@valencia]=Assigna un perfil a una imatge sense convertir-la. Comment[el]=Αντιστοιχίζει ένα προφίλ σε μια εικόνα χωρίς μετατροπή. Comment[en_GB]=Assign a profile to an image without converting it. Comment[es]=Asignar un perfil a una imagen sin convertirla. Comment[eu]=Esleitu profil bat irudi bati hura bihurtu gabe. +Comment[fi]=Liitä kuvaan profiili muuntamatta kuvaa Comment[fr]=Attribuer un profil à une image sans la convertir. Comment[gl]=Asignar un perfil a unha imaxe sen convertela. Comment[is]=Úthluta litasniði á myndina án þess að umbreyta henni. Comment[it]=Assegna un profilo a un'immagine senza convertirla. Comment[nl]=Een profiel aan een afbeelding toewijzen zonder het te converteren. Comment[pl]=Przypisz profil do obrazu bez jego przekształcania. Comment[pt]=Atribui um perfil à imagem sem a converter. Comment[pt_BR]=Atribui um perfil para uma imagem sem convertê-la. Comment[sv]=Tilldela en profil till en bild utan att konvertera den. Comment[tr]=Bir görüntüye, görüntüyü değiştirmeden bir profil ata. Comment[uk]=Призначити профіль до зображення без його перетворення. Comment[x-test]=xxAssign a profile to an image without converting it.xx Comment[zh_CN]=仅为图像指定色彩配置文件,不转换其色彩空间 Comment[zh_TW]=將設定檔指定給圖像,而不進行轉換。 diff --git a/plugins/python/colorspace/kritapykrita_colorspace.desktop b/plugins/python/colorspace/kritapykrita_colorspace.desktop index 6d70c8b0d3..75678fcd2c 100644 --- a/plugins/python/colorspace/kritapykrita_colorspace.desktop +++ b/plugins/python/colorspace/kritapykrita_colorspace.desktop @@ -1,53 +1,55 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=colorspace X-Python-2-Compatible=true X-Krita-Manual=Manual.html Name=Color Space Name[ar]=الفضاء اللوني Name[ca]=Espai de color Name[ca@valencia]=Espai de color Name[cs]=Barevný prostor Name[de]=Farbraum Name[el]=Χρωματικός χώρος Name[en_GB]=Colour Space Name[es]=Espacio de color Name[eu]=Kolore-espazioa +Name[fi]=Väriavaruus Name[fr]=Espace colorimétrique Name[gl]=Espazo de cores Name[is]=Litrýmd Name[it]=Spazio dei colori Name[nl]=Kleurruimte Name[pl]=Przestrzeń barw Name[pt]=Espaço de Cores Name[pt_BR]=Espaço de cores Name[sk]=Farebný priestor Name[sv]=Färgrymd Name[tr]=Renk Aralığı Name[uk]=Простір кольорів Name[x-test]=xxColor Spacexx Name[zh_CN]=色彩空间 Name[zh_TW]=色彩空間 Comment=Plugin to change color space to selected documents Comment[ar]=ملحقة لتغيير الفضاء اللوني في المستندات المحددة Comment[ca]=Un connector per a canviar l'espai de color dels documents seleccionats Comment[ca@valencia]=Un connector per a canviar l'espai de color dels documents seleccionats Comment[cs]=Modul pro změnu rozsahu barvy pro vybrané dokumenty Comment[el]=Πρόσθετο αλλαγής χρωματικού χώρου σε επιλεγμένα έγγραφα Comment[en_GB]=Plugin to change colour space to selected documents Comment[es]=Complemento para cambiar el espacio de color de los documentos seleccionados Comment[eu]=Hautatutako dokumentuei kolore-espazioa aldatzeko plugina +Comment[fi]=Liitännäinen valittujen tiedostojen väriavaruuden muuttamiseksi Comment[fr]=Module externe pour l'espace de couleurs des documents sélectionnés Comment[gl]=Complemento para cambiar o espazo de cores dos documentos seleccionados. Comment[it]=Estensione per cambiare lo spazio dei colori ai documenti selezionati Comment[nl]=Plug-in om kleurruimte in geselecteerde documenten te wijzigen Comment[pl]=Wtyczka do zmiany przestrzeni barw wybranych dokumentów Comment[pt]='Plugin' para mudar o espaço de cores do documento seleccionado Comment[pt_BR]=Plug-in para alterar o espaço de cores em documentos selecionados Comment[sv]=Insticksprogram för att ändra färgrymd för valda dokument Comment[tr]=Seçili belgede renk aralığını değiştirmek için eklenti Comment[uk]=Додаток для зміни простору кольорів у позначених документах Comment[x-test]=xxPlugin to change color space to selected documentsxx Comment[zh_CN]=用于更改选定文档色彩空间的插件 Comment[zh_TW]=用於變更色彩空間為選定文件的外掛程式 diff --git a/plugins/python/comics_project_management_tools/kritapykrita_comics_project_management_tools.desktop b/plugins/python/comics_project_management_tools/kritapykrita_comics_project_management_tools.desktop index 0eb67bf497..0c20dcc466 100644 --- a/plugins/python/comics_project_management_tools/kritapykrita_comics_project_management_tools.desktop +++ b/plugins/python/comics_project_management_tools/kritapykrita_comics_project_management_tools.desktop @@ -1,50 +1,52 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=comics_project_management_tools X-Krita-Manual=README.html X-Python-2-Compatible=false Name=Comics Project Management Tools Name[ar]=أدوات إدارة المشاريع الهزليّة Name[ca]=Eines per a la gestió dels projectes de còmics Name[ca@valencia]=Eines per a la gestió dels projectes de còmics Name[cs]=Nástroje pro správu projektů komixů Name[el]=Εργαλεία διαχείρισης έργων ιστοριών σε εικόνες Name[en_GB]=Comics Project Management Tools Name[es]=Herramientas de gestión de proyectos de cómics Name[eu]=Komikien proiektuak kudeatzeko tresnak +Name[fi]=Sarjakuvaprojektien hallintatyökalut Name[fr]=Outils de gestion d'un projet de bande dessinée Name[gl]=Ferramentas de xestión de proxectos de cómics Name[is]=Verkefnisstjórn teiknimyndasögu Name[it]=Strumenti per la gestione dei progetti di fumetti Name[nl]=Hulpmiddelen voor projectbeheer van strips Name[pl]=Narzędzia do zarządzania projektami komiksów Name[pt]=Ferramentas de Gestão de Projectos de Banda Desenhada Name[sv]=Projekthanteringsverktyg för tecknade serier Name[tr]=Çizgi Roman Projesi Yönetimi Araçları Name[uk]=Інструменти для керування проектами коміксів Name[x-test]=xxComics Project Management Toolsxx Name[zh_CN]=漫画项目管理工具 Name[zh_TW]=漫畫專案管理工具 Comment=Tools for managing comics. Comment[ar]=أدوات لإدارة الهزليّات. Comment[ca]=Eines per a gestionar els còmics. Comment[ca@valencia]=Eines per a gestionar els còmics. Comment[cs]=Nástroje pro správu komixů. Comment[el]=Εργαλεία για τη διαχείριση ιστοριών σε εικόνες. Comment[en_GB]=Tools for managing comics. Comment[es]=Herramientas para gestionar cómics. Comment[eu]=Komikiak kudeatzeko tresnak. +Comment[fi]=Sarjakuvien hallintatyökalut. Comment[fr]=Outils pour gérer les bandes dessinées. Comment[gl]=Ferramentas para xestionar cómics. Comment[is]=Verkfæri til að stýra gerð teiknimyndasögu. Comment[it]=Strumenti per la gestione dei fumetti. Comment[nl]=Hulpmiddelen voor beheer van strips. Comment[pl]=Narzędzie do zarządzania komiksami. Comment[pt]=Ferramentas para gerir bandas desenhadas. Comment[sv]=Verktyg för att hantera tecknade serier. Comment[tr]=Çizgi romanları yönetmek için araçlar. Comment[uk]=Інструменти для керування коміксами Comment[x-test]=xxTools for managing comics.xx Comment[zh_CN]=用于管理漫画的工具。 Comment[zh_TW]=管理漫畫的工具。 diff --git a/plugins/python/documenttools/kritapykrita_documenttools.desktop b/plugins/python/documenttools/kritapykrita_documenttools.desktop index d57e33810f..ba70498fa1 100644 --- a/plugins/python/documenttools/kritapykrita_documenttools.desktop +++ b/plugins/python/documenttools/kritapykrita_documenttools.desktop @@ -1,50 +1,52 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=documenttools X-Python-2-Compatible=true X-Krita-Manual=Manual.html Name=Document Tools Name[ar]=أدوات المستندات Name[ca]=Eines de document Name[ca@valencia]=Eines de document Name[cs]=Dokumentové nástroje Name[el]=Εργαλεία για έγγραφα Name[en_GB]=Document Tools Name[es]=Herramientas de documentos Name[eu]=Dokumentuen tresnak +Name[fi]=Tiedostotyökalut Name[fr]=Outil Document Name[gl]=Ferramentas de documentos Name[it]=Strumenti per i documenti Name[nl]=Documenthulpmiddelen Name[pl]=Narzędzia dokumentu Name[pt]=Ferramentas de Documentos Name[pt_BR]=Ferramentas de documento Name[sv]=Dokumentverktyg Name[tr]=Belge Araçları Name[uk]=Засоби документа Name[x-test]=xxDocument Toolsxx Name[zh_CN]=文档工具 Name[zh_TW]=文件工具 Comment=Plugin to manipulate properties of selected documents Comment[ar]=ملحقة لتعديل خصائص المستندات المحددة Comment[ca]=Un connector per a manipular les propietats dels documents seleccionats Comment[ca@valencia]=Un connector per a manipular les propietats dels documents seleccionats Comment[cs]=Modul pro správu vlastností vybraných dokumentů Comment[el]=Πρόσθετο χειρισμού ιδιοτήτων σε επιλεγμένα έγγραφα Comment[en_GB]=Plugin to manipulate properties of selected documents Comment[es]=Complemento para manipular las propiedades de los documentos seleccionados Comment[eu]=Hautatutako dokumentuen propietateak manipulatzeko plugina +Comment[fi]=Liitännäinen valittujen tiedostojen ominaisuuksien käsittelemiseksi Comment[fr]=Module externe de gestion des propriétés des documents sélectionnés Comment[gl]=Complemento para manipular as propiedades dos documentos seleccionados. Comment[it]=Estensione per manipolare le proprietà dei documenti selezionati Comment[nl]=Plug-in om eigenschappen van geselecteerde documenten te manipuleren Comment[pl]=Wtyczka do zmiany właściwości wybranych dokumentów Comment[pt]='Plugin' para manipular as propriedades dos documentos seleccionados Comment[pt_BR]=Plug-in para manipular as propriedades de documentos selecionados Comment[sv]=Insticksprogram för att ändra egenskaper för valda dokument Comment[tr]=Seçili belgelerin özelliklerini değiştirmek için eklenti Comment[uk]=Додаток для керування властивостями позначених документів Comment[x-test]=xxPlugin to manipulate properties of selected documentsxx Comment[zh_CN]=用于编辑选定文档属性的插件 Comment[zh_TW]=用於修改所選文件屬性的外掛程式 diff --git a/plugins/python/exportlayers/kritapykrita_exportlayers.desktop b/plugins/python/exportlayers/kritapykrita_exportlayers.desktop index 88a079257b..860a93c3fb 100644 --- a/plugins/python/exportlayers/kritapykrita_exportlayers.desktop +++ b/plugins/python/exportlayers/kritapykrita_exportlayers.desktop @@ -1,53 +1,55 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=exportlayers X-Krita-Manual=Manual.html X-Python-2-Compatible=true Name=Export Layers Name[ar]=تصدير الطبقات Name[ca]=Exportació de capes Name[ca@valencia]=Exportació de capes Name[cs]=Exportovat vrstvy Name[de]=Ebenen exportieren Name[el]=Εξαγωγή επιπέδων Name[en_GB]=Export Layers Name[es]=Exportar capas Name[eu]=Esportatu geruzak +Name[fi]=Vie tasoja Name[fr]=Exporter des calques Name[gl]=Exportar as capas Name[is]=Flytja út lög Name[it]=Esporta livelli Name[nl]=Lagen exporteren Name[pl]=Eksportuj warstwy Name[pt]=Exportar as Camadas Name[pt_BR]=Exportar camadas Name[sv]=Exportera lager Name[tr]=Katmanları Dışa Aktar Name[uk]=Експортувати шари Name[x-test]=xxExport Layersxx Name[zh_CN]=导出图层 Name[zh_TW]=匯出圖層 Comment=Plugin to export layers from a document Comment[ar]=ملحقة لتصدير الطبقات من مستند Comment[ca]=Un connector per exportar capes d'un document Comment[ca@valencia]=Un connector per exportar capes d'un document Comment[cs]=Modul pro export vrstev z dokumentu Comment[de]=Modul zum Exportieren von Ebenen aus einem Dokument Comment[el]=Πρόσθετο εξαγωγής επιπέδων από έγγραφο Comment[en_GB]=Plugin to export layers from a document Comment[es]=Complemento para exportar las capas de un documento Comment[eu]=Dokumentu batetik geruzak esportatzeko plugina +Comment[fi]=Liitännäisen tiedoston tasojen viemiseksi Comment[fr]=Module externe d'export de calques d'un document Comment[gl]=Complemento para exportar as capas dun documento. Comment[it]=Estensione per esportare i livelli da un documento Comment[nl]=Plug-in om lagen uit een document te exporteren Comment[pl]=Wtyczka do eksportowania warstw z dokumentu Comment[pt]='Plugin' para exportar as camadas de um documento Comment[pt_BR]=Plug-in para exportar as camadas de um documento Comment[sv]=Insticksprogram för att exportera lager från ett dokument Comment[tr]=Belgenin katmanlarını dışa aktarmak için eklenti Comment[uk]=Додаток для експортування шарів з документа Comment[x-test]=xxPlugin to export layers from a documentxx Comment[zh_CN]=用于从文档导出图层的插件 Comment[zh_TW]=用於從文件匯出圖層的外掛程式 diff --git a/plugins/python/filtermanager/kritapykrita_filtermanager.desktop b/plugins/python/filtermanager/kritapykrita_filtermanager.desktop index a40a8a94f5..3c7c53f7ef 100644 --- a/plugins/python/filtermanager/kritapykrita_filtermanager.desktop +++ b/plugins/python/filtermanager/kritapykrita_filtermanager.desktop @@ -1,52 +1,54 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=filtermanager X-Python-2-Compatible=true X-Krita-Manual=Manual.html Name=Filter Manager Name[ar]=مدير المرشّحات Name[ca]=Gestor de filtres Name[ca@valencia]=Gestor de filtres Name[cs]=Správce filtrů Name[de]=Filterverwaltung Name[el]=Διαχειριστής φίλτρων Name[en_GB]=Filter Manager Name[es]=Gestor de filtros Name[eu]=Iragazki-kudeatzailea +Name[fi]=Suodatinhallinta Name[fr]=Gestionnaire de fichiers Name[gl]=Xestor de filtros Name[it]=Gestore dei filtri Name[nl]=Beheerder van filters Name[pl]=Zarządzanie filtrami Name[pt]=Gestor de Filtros Name[pt_BR]=Gerenciador de filtros Name[sv]=Filterhantering Name[tr]=Süzgeç Yöneticisi Name[uk]=Керування фільтрами Name[x-test]=xxFilter Managerxx Name[zh_CN]=滤镜管理器 Name[zh_TW]=濾鏡管理器 Comment=Plugin to filters management Comment[ar]=ملحقة إدارة المرشّحات Comment[ca]=Un connector per a gestionar filtres Comment[ca@valencia]=Un connector per a gestionar filtres Comment[cs]=Modul pro správu filtrů Comment[de]=Modul zum Verwalten von Filtern Comment[el]=Πρόσθετο για τη διαχείριση φίλτρων Comment[en_GB]=Plugin to filters management Comment[es]=Complemento para la gestión de filtros Comment[eu]=Iragazkiak kudeatzeko plugina +Comment[fi]=Liitännäinen suodatinten hallintaan Comment[fr]=Module externe de gestion des filtres Comment[gl]=Complemento para a xestión de filtros. Comment[it]=Estensione per la gestione dei filtri Comment[nl]=Plug-in voor beheer van filters Comment[pl]=Wtyczka do zarządzania filtrami Comment[pt]='Plugin' para a gestão de filtros Comment[pt_BR]=Plug-in para gerenciamento de filtros Comment[sv]=Insticksprogram för filterhantering Comment[tr]=Süzgeç yönetimi için eklenti Comment[uk]=Додаток для керування фільтрами Comment[x-test]=xxPlugin to filters managementxx -Comment[zh_CN]=滤镜管理插件 +Comment[zh_CN]=用于管理滤镜的插件。 Comment[zh_TW]=用於濾鏡管理的外掛程式 diff --git a/plugins/python/hello/kritapykrita_hello.desktop b/plugins/python/hello/kritapykrita_hello.desktop index 9cc1af0736..5aad8676cd 100644 --- a/plugins/python/hello/kritapykrita_hello.desktop +++ b/plugins/python/hello/kritapykrita_hello.desktop @@ -1,54 +1,56 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=hello X-Krita-Manual=Manual.html X-Python-2-Compatible=true Name=Hello World Name[ar]=مرحبا يا عالم Name[ca]=Hola món Name[ca@valencia]=Hola món Name[cs]=Hello World Name[de]=Hallo Welt Name[el]=Hello World Name[en_GB]=Hello World Name[es]=Hola mundo Name[eu]=Kaixo mundua +Name[fi]=Hei maailma Name[fr]=Bonjour tout le monde Name[gl]=Ola mundo Name[is]=Halló Heimur Name[it]=Ciao mondo Name[nl]=Hallo wereld Name[pl]=Witaj świecie Name[pt]=Olá Mundo Name[pt_BR]=Olá mundo Name[sk]=Ahoj svet Name[sv]=Hello World Name[tr]=Merhaba Dünya Name[uk]=Привіт, світе Name[x-test]=xxHello Worldxx Name[zh_CN]=Hello World Name[zh_TW]=你好,世界 Comment=Basic plugin to test PyKrita Comment[ar]=ملحقة أساسية لاختبار PyKrita Comment[ca]=Connector bàsic per provar el PyKrita Comment[ca@valencia]=Connector bàsic per provar el PyKrita Comment[cs]=Základní modul pro testování PyKrita Comment[de]=Basismodul zum Testen von PyKrita Comment[el]=Βασικό πρόσθετο δοκιμής PyKrita Comment[en_GB]=Basic plugin to test PyKrita Comment[es]=Complemento básico para probar PyKrita Comment[eu]=PyKrita probatzeko plugina +Comment[fi]=Perusliitännäinen PyKritan kokeilemiseksi Comment[fr]=Module externe élémentaire pour tester PyKrita Comment[gl]=Complemento básico para probar PyKrita. Comment[it]=Estensione di base per provare PyKrita Comment[nl]=Basisplug-in om PyKrita te testen Comment[pl]=Podstawowa wtyczka do wypróbowania PyKrity Comment[pt]='Plugin' básico para testar o PyKrita Comment[pt_BR]=Plug-in básico para testar o PyKrita Comment[sv]=Enkelt insticksprogram för att utprova PyKrita Comment[tr]=PyKrita'yı test etmek için temel eklenti Comment[uk]=Базовий додаток для тестування PyKrita Comment[x-test]=xxBasic plugin to test PyKritaxx Comment[zh_CN]=用于测试 PyKrita 的简易插件 Comment[zh_TW]=測試 PyKrita 的基本外掛程式 diff --git a/plugins/python/krita_script_starter/kritapykrita_krita_script_starter.desktop b/plugins/python/krita_script_starter/kritapykrita_krita_script_starter.desktop index f9f11aa2ac..4f7854fb9f 100644 --- a/plugins/python/krita_script_starter/kritapykrita_krita_script_starter.desktop +++ b/plugins/python/krita_script_starter/kritapykrita_krita_script_starter.desktop @@ -1,39 +1,39 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=krita_script_starter X-Python-2-Compatible=false X-Krita-Manual=Manual.html Name=Krita Script Starter Name[ca]=Iniciador de scripts del Krita Name[ca@valencia]=Iniciador de scripts del Krita Name[cs]=Spouštěč skriptů Krita Name[en_GB]=Krita Script Starter Name[es]=Iniciador de guiones de Krita Name[eu]=Krita-ren script abiarazlea Name[gl]=Iniciador de scripts de Krita Name[it]=Iniziatore di script per Krita Name[nl]=Script-starter van Krita Name[pl]=Starter skryptów Krity Name[pt]=Inicialização do Programa do Krita Name[sv]=Krita skriptstart Name[uk]=Створення скрипту Krita Name[x-test]=xxKrita Script Starterxx Name[zh_CN]=Krita 空脚本生成器 Name[zh_TW]=Krita 指令啟動器 Comment=Create the metadata and file structure for a new Krita script Comment[ca]=Crea les metadades i l'estructura de fitxers d'un script nou del Krita Comment[ca@valencia]=Crea les metadades i l'estructura de fitxers d'un script nou del Krita Comment[en_GB]=Create the metadata and file structure for a new Krita script Comment[es]=Crear los metadatos y la estructura de archivos para un nuevo guion de Krita Comment[eu]=Sortu Krita-script berri baterako meta-datuak eta fitxategi egitura Comment[gl]=Crear os metadatos e a estrutura de ficheiros para un novo script de Krita. Comment[it]=Crea i metadati e la struttura dei file per un nuovo script di Krita Comment[nl]=Maak de metagegevens en bestandsstructuur voor een nieuw Krita-script Comment[pl]=Utwórz metadane i strukturę plików dla nowego skryptu Krity Comment[pt]=Cria os meta-dados e a estrutura de ficheiros para um novo programa do Krita Comment[sv]=Skapa metadata och filstruktur för ett nytt Krita-skript Comment[uk]=Створення метаданих і структури файлів для нового скрипту Krita Comment[x-test]=xxCreate the metadata and file structure for a new Krita scriptxx -Comment[zh_CN]=给一个新 Krita 脚本创建元数据及文件结构 +Comment[zh_CN]=为新的 Krita 脚本创建元数据及文件结构 Comment[zh_TW]=為新的 Krita 腳本建立中繼資料和檔案建構體 diff --git a/plugins/python/lastdocumentsdocker/kritapykrita_lastdocumentsdocker.desktop b/plugins/python/lastdocumentsdocker/kritapykrita_lastdocumentsdocker.desktop index f3789d0b59..df847362ee 100644 --- a/plugins/python/lastdocumentsdocker/kritapykrita_lastdocumentsdocker.desktop +++ b/plugins/python/lastdocumentsdocker/kritapykrita_lastdocumentsdocker.desktop @@ -1,46 +1,48 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=lastdocumentsdocker X-Python-2-Compatible=false X-Krita-Manual=Manual.html Name=Last Documents Docker Name[ar]=رصيف بآخر المستندات Name[ca]=Acoblador dels darrers documents Name[ca@valencia]=Acoblador dels darrers documents Name[el]=Προσάρτηση τελευταίων εγγράφοων Name[en_GB]=Last Documents Docker Name[es]=Panel de últimos documentos Name[eu]=Azken dokumentuen panela +Name[fi]=Viimeisimpien tiedostojen telakka Name[fr]=Récemment ouverts Name[gl]=Doca dos últimos documentos Name[it]=Area di aggancio Ultimi documenti Name[nl]=Laatste documenten verankering Name[pl]=Dok ostatnich dokumentów Name[pt]=Área dos Últimos Documentos Name[sv]=Dockningsfönster för senaste dokument Name[tr]=Son Belgeler Doku Name[uk]=Бічна панель останніх документів Name[x-test]=xxLast Documents Dockerxx Name[zh_CN]=最近文档工具面板 Name[zh_TW]=「最後文件」面板 Comment=A Python-based docker for show thumbnails to last ten documents Comment[ar]=رصيف بِ‍«پيثون» لعرض مصغّرات آخر ١٠ مستندات مفتوحة Comment[ca]=Un acoblador basant en el Python per a mostrar miniatures dels darrers deu documents Comment[ca@valencia]=Un acoblador basant en el Python per a mostrar miniatures dels darrers deu documents Comment[el]=Ένα εργαλείο προσάρτησης σε Python για την εμφάνιση επισκοπήσεων των δέκα τελευταίων εγγράφων Comment[en_GB]=A Python-based docker for show thumbnails to last ten documents Comment[es]=Un panel basado en Python para mostrar miniaturas de los últimos diez documentos Comment[eu]=Azken hamar dokumentuen koadro-txikiak erakusteko Python-oinarridun panel bat +Comment[fi]=Python-pohjainen telakka viimeisimpien kymmenen tiedoston pienoiskuvien näyttämiseen Comment[fr]=Panneau en Python pour afficher les vignettes des dix derniers documents Comment[gl]=Unha doca baseada en Python para mostrar as miniaturas dos últimos dez documentos. Comment[it]=Un'area di aggancio basata su Python per mostrare miniature degli ultimi dieci documenti. Comment[nl]=Een op Python gebaseerde vastzetter om miniaturen te tonen naar de laatste tien documenten. Comment[pl]=Dok oparty na pythonie do wyświetlania miniatur ostatnich dziesięciu dokumentów Comment[pt]=Uma área acoplável, feita em Python, para mostrar as miniaturas dos últimos dez documentos Comment[sv]=Ett Python-baserat dockningsfönster för att visa miniatyrbilder för de tio senaste dokumenten Comment[tr]=Son on belgenin küçük resmini göstermek için Python-tabanlı bir dok Comment[uk]=Бічна панель на основі Python для показу мініатюр останніх десяти документів Comment[x-test]=xxA Python-based docker for show thumbnails to last ten documentsxx Comment[zh_CN]=基于 Python 的工具面板,显示最近十个文档的缩略图 Comment[zh_TW]=基於 Python 的面板,用於顯示最後 10 個文件縮圖 diff --git a/plugins/python/palette_docker/kritapykrita_palette_docker.desktop b/plugins/python/palette_docker/kritapykrita_palette_docker.desktop index 1885104099..89e5716c7c 100644 --- a/plugins/python/palette_docker/kritapykrita_palette_docker.desktop +++ b/plugins/python/palette_docker/kritapykrita_palette_docker.desktop @@ -1,49 +1,51 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=palette_docker X-Python-2-Compatible=true X-Krita-Manual=Manual.html Name=Palette docker Name[ar]=رصيف اللوحات Name[ca]=Acoblador de paletes Name[ca@valencia]=Acoblador de paletes Name[cs]=Dok palet Name[de]=Paletten-Docker Name[el]=Προσάρτηση παλέτας Name[en_GB]=Palette docker Name[es]=Panel de paleta Name[eu]=Paleta-panela +Name[fi]=Palettitelakka Name[fr]=Panneau de palette Name[gl]=Doca de paleta Name[is]=Tengikví fyrir litaspjald Name[it]=Area di aggancio della tavolozza Name[nl]=Vastzetter van palet Name[pl]=Dok palety Name[pt]=Área acoplável da paleta Name[sv]=Dockningsfönster för palett Name[tr]=Palet doku Name[uk]=Панель палітри Name[x-test]=xxPalette dockerxx Name[zh_CN]=调色板工具面板 Name[zh_TW]=「調色盤」面板 Comment=A Python-based docker to edit color palettes. Comment[ar]=رصيف بِ‍«پيثون» لتحرير لوحات الألوان. Comment[ca]=Un acoblador basant en el Python per editar paletes de colors. Comment[ca@valencia]=Un acoblador basant en el Python per editar paletes de colors. Comment[el]=Ένα εργαλείο προσάρτησης σε Python για την επεξεργασία παλετών χρώματος. Comment[en_GB]=A Python-based docker to edit colour palettes. Comment[es]=Un panel basado en Python para editar paletas de colores. Comment[eu]=Kolore-paletak editatzeko Python-oinarridun paleta bat. +Comment[fi]=Python-pohjainen telakka väripalettien muokkaamiseen. Comment[fr]=Panneau en Python pour éditer les palettes de couleurs. Comment[gl]=Unha doca baseada en Python para editar paletas de cores. Comment[it]=Un'area di aggancio per modificare le tavolozze di colori basata su Python. Comment[nl]=Een op Python gebaseerde vastzetter om kleurpaletten te bewerken. Comment[pl]=Dok oparty na pythonie do edytowania palet barw. Comment[pt]=Uma área acoplável, feita em Python, para editar paletas de cores. Comment[sv]=Ett Python-baserat dockningsfönster för att redigera färgpaletter. Comment[tr]=Renk paletlerini düzenlemek için Python-tabanlı bir dok. Comment[uk]=Бічна панель для редагування палітр кольорів на основі Python. Comment[x-test]=xxA Python-based docker to edit color palettes.xx Comment[zh_CN]=基于 Python 的调色板编辑器工具面板 Comment[zh_TW]=基於 Python 的面板,用於編輯調色盤。 diff --git a/plugins/python/quick_settings_docker/kritapykrita_quick_settings_docker.desktop b/plugins/python/quick_settings_docker/kritapykrita_quick_settings_docker.desktop index 227082f715..ec826415a2 100644 --- a/plugins/python/quick_settings_docker/kritapykrita_quick_settings_docker.desktop +++ b/plugins/python/quick_settings_docker/kritapykrita_quick_settings_docker.desktop @@ -1,47 +1,49 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=quick_settings_docker X-Python-2-Compatible=true X-Krita-Manual=Manual.html Name=Quick Settings Docker Name[ar]=رصيف بإعدادات سريعة Name[ca]=Acoblador d'arranjament ràpid Name[ca@valencia]=Acoblador d'arranjament ràpid Name[cs]=Dok pro rychlé nastavení Name[el]=Προσάρτηση γρήγορων ρυθμίσεων Name[en_GB]=Quick Settings Docker Name[es]=Panel de ajustes rápidos Name[eu]=Ezarpen azkarren panela +Name[fi]=Pika-asetustelakka Name[fr]=Réglages rapides Name[gl]=Doca de configuración rápida Name[it]=Area di aggancio delle impostazioni rapide Name[nl]=Verankering voor snelle instellingen Name[pl]=Dok szybkich ustawień Name[pt]=Área de Configuração Rápida Name[sv]=Dockningspanel med snabbinställningar Name[tr]=Hızlı Ayarlar Doku Name[uk]=Панель швидких параметрів Name[x-test]=xxQuick Settings Dockerxx Name[zh_CN]=快速设置工具面板 Name[zh_TW]=「快速設定」面板 Comment=A Python-based docker for quickly changing brush size and opacity. Comment[ar]=رصيف بِ‍«پيثون» لتغيير حجم الفرشاة وشفافيّتها بسرعة. Comment[ca]=Un acoblador basat en el Python per a canviar ràpidament la mida i l'opacitat del pinzell. Comment[ca@valencia]=Un acoblador basat en el Python per a canviar ràpidament la mida i l'opacitat del pinzell. Comment[el]=Ένα εργαλείο προσάρτησης σε Python για γρήγορη αλλαγή του μεγέθους και της αδιαφάνειας του πινέλου. Comment[en_GB]=A Python-based docker for quickly changing brush size and opacity. Comment[es]=Un panel basado en Python para cambiar rápidamente el tamaño y la opacidad del pincel. Comment[eu]=Isipu-neurria eta -opakotasuna aldatzeko Python-oinarridun panel bat. +Comment[fi]=Python-pohjainen telakka siveltimen koon ja läpikuultavuuden nopean muuttamiseen. Comment[fr]=Panneau en python pour modifier rapidement la taille et l'opacité des brosses. Comment[gl]=Unha doca baseada en Python para cambiar rapidamente a opacidade e o tamaño dos pinceis. Comment[it]=Un'area di aggancio basata su Python per cambiare rapidamente la dimensione del pennello e l'opacità. Comment[nl]=Een op Python gebaseerde docker voor snel wijzigen van penseelgrootte en dekking. Comment[pl]=Dok oparty na pythonie do szybkiej zmiany rozmiaru i nieprzezroczystości pędzla. Comment[pt]=Uma área acoplável em Python para mudar rapidamente o tamanho e opacidade do pincel. Comment[sv]=En Python-baserad dockningspanel för att snabbt ändra penselstorlek och ogenomskinlighet. Comment[tr]=Fırça boyutunu ve matlığını hızlıca değiştirmek için Python-tabanlı bir dok. Comment[uk]=Панель на основі мови програмування Python для швидкої зміни розміру та непрозорості пензля. Comment[x-test]=xxA Python-based docker for quickly changing brush size and opacity.xx Comment[zh_CN]=基于 Python 的用于快速更改笔刷尺寸和透明度的工具面板。 Comment[zh_TW]=基於 Python 的面板,用於快速變更筆刷尺寸和不透明度。 diff --git a/plugins/python/scriptdocker/kritapykrita_scriptdocker.desktop b/plugins/python/scriptdocker/kritapykrita_scriptdocker.desktop index 695fe77a3c..5c2439093d 100644 --- a/plugins/python/scriptdocker/kritapykrita_scriptdocker.desktop +++ b/plugins/python/scriptdocker/kritapykrita_scriptdocker.desktop @@ -1,45 +1,46 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=scriptdocker X-Python-2-Compatible=false Name=Script Docker Name[ar]=رصيف سكربتات Name[ca]=Acoblador de scripts Name[ca@valencia]=Acoblador de scripts Name[cs]=Dok skriptu Name[el]=Προσάρτηση σεναρίων Name[en_GB]=Script Docker Name[es]=Panel de guiones Name[eu]=Script-panela +Name[fi]=Skriptitelakka Name[fr]=Panneau de script Name[gl]=Doca de scripts Name[it]=Area di aggancio degli script Name[nl]=Verankering van scripts Name[pl]=Dok skryptów Name[pt]=Área de Programas Name[sv]=Dockningsfönster för skript Name[tr]=Betik Doku Name[uk]=Бічна панель скриптів Name[x-test]=xxScript Dockerxx Name[zh_CN]=脚本工具面板 Name[zh_TW]=「腳本」面板 Comment=A Python-based docker for create actions and point to Python scripts Comment[ar]=رصيف بِ‍«پيثون» لإنشاء الإجراءات والإشارة إلى سكربتات «پيثون» Comment[ca]=Un acoblador basat en el Python per a crear accions i apuntar a scripts de Python Comment[ca@valencia]=Un acoblador basat en el Python per a crear accions i apuntar a scripts de Python Comment[el]=Ένα εργαλείο προσάρτησης σε Python για τη δημιουργία ενεργειών και τη δεικτοδότηση σεναρίων σε Python Comment[en_GB]=A Python-based docker for create actions and point to Python scripts Comment[es]=Un panel basado en Python para crear y apuntar a guiones de Python Comment[eu]=Python-oinarridun panel bat. Comment[gl]=Unha doca escrita en Python para crear accións e apuntar a scripts escritos en Python. Comment[it]=Un'area di aggancio basata su Python per creare azioni e scegliere script Python Comment[nl]=Een op Python gebaseerde vastzetter voor aanmaakacties en wijzen naar Python-scripts Comment[pl]=Dok oparty na pythonie do tworzenia działań i punktów dla skryptów pythona Comment[pt]=Uma área acoplável, feita em Python, para criar acções e apontar para programas em Python Comment[sv]=Ett Python-baserat dockningsfönster för att skapa åtgärder och peka ut Python-skript Comment[tr]=Eylemler oluşturmak ve Python betiklerine yönlendirmek için Python-tabanlı bir dok Comment[uk]=Бічна панель для створення дій і керування скриптами на основі Python. Comment[x-test]=xxA Python-based docker for create actions and point to Python scriptsxx Comment[zh_CN]=基于 Python 的用于创建动作并指向 Python 脚本的工具面板 Comment[zh_TW]=基於 Python 的面板,用於建立動作並指向 Python 腳本 diff --git a/plugins/python/scripter/kritapykrita_scripter.desktop b/plugins/python/scripter/kritapykrita_scripter.desktop index 1b92a8fea1..ef5d9e192d 100644 --- a/plugins/python/scripter/kritapykrita_scripter.desktop +++ b/plugins/python/scripter/kritapykrita_scripter.desktop @@ -1,44 +1,45 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=scripter X-Python-2-Compatible=true X-Krita-Manual=Manual.html Name=Scripter Name[ca]=Scripter Name[ca@valencia]=Scripter Name[de]=Scripter Name[el]=Σενάρια Name[en_GB]=Scripter Name[es]=Guionador Name[eu]=Script egilea Name[fr]=Scripter Name[gl]=Executor de scripts Name[it]=Scripter Name[nl]=Scriptmaker Name[pl]=Skrypter Name[pt]=Programador Name[sv]=Skriptgenerator Name[tr]=Betik yazarı Name[uk]=Скриптер Name[x-test]=xxScripterxx Name[zh_CN]=脚本编写器 Name[zh_TW]=腳本編寫者 Comment=Plugin to execute ad-hoc Python code Comment[ca]=Connector per executar codi Python ad hoc Comment[ca@valencia]=Connector per executar codi Python ad hoc Comment[el]=Πρόσθετο για την εκτέλεση συγκεκριμένου κώδικα Python Comment[en_GB]=Plugin to execute ad-hoc Python code Comment[es]=Complemento para ejecutar código Python a medida Comment[eu]=Berariaz egindako Python kodea exekutatzeko plugina +Comment[fi]=Liitännäinen satunnaisen Python-koodin suorittamiseksi Comment[gl]=Complemento para executar código de Python escrito no momento. Comment[it]=Estensione per eseguire ad-hoc codice Python Comment[nl]=Plug-in om ad-hoc Python code uit te voeren Comment[pl]=Wtyczka do wykonywania kodu Pythona ad-hoc Comment[pt]='Plugin' para executar código em Python arbitrário Comment[sv]=Insticksprogram för att köra godtycklig Python-kod Comment[tr]=Geçici Python kodu çalıştırmak için eklenti Comment[uk]=Додаток для виконання апріорного коду Python Comment[x-test]=xxPlugin to execute ad-hoc Python codexx -Comment[zh_CN]=执行现场编写的 Python 代码的插件 +Comment[zh_CN]=用于执行当场编写的 Python 代码的插件 Comment[zh_TW]=外掛程式,用於執行特定 Python 程式碼 diff --git a/plugins/python/selectionsbagdocker/kritapykrita_selectionsbagdocker.desktop b/plugins/python/selectionsbagdocker/kritapykrita_selectionsbagdocker.desktop index d79d012a89..58b48d5972 100644 --- a/plugins/python/selectionsbagdocker/kritapykrita_selectionsbagdocker.desktop +++ b/plugins/python/selectionsbagdocker/kritapykrita_selectionsbagdocker.desktop @@ -1,45 +1,46 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=selectionsbagdocker X-Python-2-Compatible=false Name=Selections Bag Docker Name[ca]=Acoblador de bossa de seleccions Name[ca@valencia]=Acoblador de bossa de seleccions Name[el]=Προσάρτηση σάκου επιλογών Name[en_GB]=Selections Bag Docker Name[es]=Panel de selecciones Name[eu]=Hautapen-zakua panela Name[fr]=Outils de sélection Name[gl]=Doca de bolsa das seleccións Name[it]=Area di raccolta selezioni Name[nl]=Docker van zak met selecties Name[pl]=Dok worka zaznaczeń Name[pt]=Área de Selecções Name[sv]=Dockningspanel med markeringspåse Name[tr]=Seçim Çantası Doku Name[uk]=Бічна панель позначеного Name[x-test]=xxSelections Bag Dockerxx Name[zh_CN]=选区列表工具面板 Name[zh_TW]=「選取範圍收藏」面板 Comment=A docker that allow to store a list of selections Comment[ar]=رصيف يتيح تخزين قائمة تحديدات Comment[ca]=Un acoblador que permet emmagatzemar una llista de seleccions Comment[ca@valencia]=Un acoblador que permet emmagatzemar una llista de seleccions Comment[cs]=Dok umožňující uložit seznam výběrů Comment[el]=Ένα εργαλείο προσάρτησης που επιτρέπει την αποθήκευση μιας λίστας επιλογών Comment[en_GB]=A docker that allow to store a list of selections Comment[es]=Un panel que permite guardar una lista de selecciones Comment[eu]=Hautapen zerrenda bat biltegiratzen uzten duen panel bat +Comment[fi]=Telakka, joka sallii tallentaa valintaluettelon Comment[fr]=Panneau permettant de conserver une liste de sélections Comment[gl]=Unha doca que permite almacenar unha lista de seleccións. Comment[it]=Un'area di aggancio che consente di memorizzare un elenco di selezioni Comment[nl]=Een docker die een lijst met selecties kan opslaan Comment[pl]=Dok, który umożliwia przechowywanie listy zaznaczeń Comment[pt]=Uma área acoplável que permite guardar uma lista de selecções Comment[sv]=En dockningspanel som gör det möjligt att lagra en lista över markeringar Comment[tr]=Seçimlerin bir listesini saklamayı sağlayan bir dok Comment[uk]=Бічна панель, на якій можна зберігати список позначеного Comment[x-test]=xxA docker that allow to store a list of selectionsxx -Comment[zh_CN]=用于保存一系列选区的工具面板 +Comment[zh_CN]=用于保存一组选区的工具面板 Comment[zh_TW]=允許儲存選取範圍列表的面板 diff --git a/plugins/python/tenbrushes/kritapykrita_tenbrushes.desktop b/plugins/python/tenbrushes/kritapykrita_tenbrushes.desktop index 79d39a329f..c5378ba5dd 100644 --- a/plugins/python/tenbrushes/kritapykrita_tenbrushes.desktop +++ b/plugins/python/tenbrushes/kritapykrita_tenbrushes.desktop @@ -1,46 +1,48 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=tenbrushes X-Python-2-Compatible=true X-Krita-Manual=Manual.html Name=Ten Brushes Name[ar]=عشرُ فُرش Name[ca]=Deu pinzells Name[ca@valencia]=Deu pinzells Name[cs]=Deset štětců Name[el]=Δέκα πινέλα Name[en_GB]=Ten Brushes Name[es]=Diez pinceles Name[eu]=Hamar isipu +Name[fi]=Kymmenen sivellintä Name[fr]=Raccourcis des préréglages de brosses Name[gl]=Dez pinceis Name[is]=Tíu penslar Name[it]=Dieci pennelli Name[nl]=Tien penselen Name[pl]=Dziesięć pędzli Name[pt]=Dez Pincéis Name[sv]=Tio penslar Name[tr]=On Fırça Name[uk]=Десять пензлів Name[x-test]=xxTen Brushesxx Name[zh_CN]=十大笔刷 Name[zh_TW]=10 個筆刷 Comment=Assign a preset to ctrl-1 to ctrl-0 Comment[ca]=Assigna una predefinició des de Ctrl-1 a Ctrl-0 Comment[ca@valencia]=Assigna una predefinició des de Ctrl-1 a Ctrl-0 Comment[el]=Αντιστοίχιση προκαθορισμένου από ctrl-1 στο ctrl-0 Comment[en_GB]=Assign a preset to ctrl-1 to ctrl-0 Comment[es]=Asignar una preselección a Ctrl-1 hasta Ctrl-0 Comment[eu]=Aurrezarpena ezarri ktrl-1'etik ktrl-0'ra arte +Comment[fi]=Kytke esiasetukset Ctrl-1:stä Ctrl-0:aan Comment[gl]=Asigne unha predefinición do Ctrl+1 ao Ctrl+0. Comment[it]=Assegna una preimpostazione per ctrl-1 a ctrl-0 Comment[nl]=Een voorinstelling toekennen aan Ctrl-1 tot Ctrl-0 Comment[pl]=Przypisz nastawę do ctrl-1 lub ctrl-0 Comment[pt]=Atribuir uma predefinição de Ctrl-1 a Ctrl-0 Comment[sv]=Tilldela en förinställning för Ctrl+1 till Ctrl+0 Comment[tr]= ctrl-1 ve ctrl-0 için ayar atama Comment[uk]=Прив’язування наборів налаштувань до скорочень від ctrl-1 до ctrl-0 Comment[x-test]=xxAssign a preset to ctrl-1 to ctrl-0xx -Comment[zh_CN]=将预设分配给 Ctrl+1 到 Ctrl+0 快捷键 +Comment[zh_CN]=将预设分配给由 Ctrl+1 到 Ctrl+0 的快捷键 Comment[zh_TW]=將預設指定給 ctrl-1 至 ctrl-0 diff --git a/plugins/python/tenscripts/kritapykrita_tenscripts.desktop b/plugins/python/tenscripts/kritapykrita_tenscripts.desktop index c6484d1cf3..24ca96d74d 100644 --- a/plugins/python/tenscripts/kritapykrita_tenscripts.desktop +++ b/plugins/python/tenscripts/kritapykrita_tenscripts.desktop @@ -1,43 +1,45 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=tenscripts X-Python-2-Compatible=true X-Krita-Manual=Manual.html Name=Ten Scripts Name[ar]=عشرُ سكربتات Name[ca]=Deu scripts Name[ca@valencia]=Deu scripts Name[en_GB]=Ten Scripts Name[es]=Diez guiones Name[eu]=Hamar script +Name[fi]=Kymmenen skriptiä Name[fr]=Raccourcis des scripts Name[gl]=Dez scripts Name[is]=Tíu skriftur Name[it]=Dieci script Name[nl]=Tien scripts Name[pl]=Skrypty Ten Name[pt]=Dez Programas Name[sv]=Tio skript Name[uk]=Десять скриптів Name[x-test]=xxTen Scriptsxx Name[zh_CN]=十大脚本 Name[zh_TW]=10 個腳本 Comment=A Python-based plugin for creating ten actions and assign them to Python scripts Comment[ar]=ملحقة بِ‍«پيثون» لإنشاء ١٠ إجراءات وإسنادها إلى سكربتات «پيثون» Comment[ca]=Un connector basat en el Python per a crear deu accions i assignar-les a scripts de Python Comment[ca@valencia]=Un connector basat en el Python per a crear deu accions i assignar-les a scripts de Python Comment[en_GB]=A Python-based plugin for creating ten actions and assign them to Python scripts Comment[es]=Un complemento basado en Python para crear diez acciones y asignarlas a guiones de Python Comment[eu]=Hamar ekintza sortu eta haiek Python-scriptei esleitzeko Python-oinarridun plugin bat +Comment[fi]=Python-pohjainen liitännäinen kymmenen toiminnon luomiseksi kytkemiseksi Python-skripteihin Comment[fr]=Module externe basé sur Python pour créer dix actions et les assigner à des scripts Python Comment[gl]=Un complemento escrito en Python para crear dez accións e asignalas a scripts escritos en Python. Comment[it]=Un'estensione basata su Python per creare dieci azioni e assegnarle a script Python Comment[nl]=Een op Python gebaseerde plug-in voor aanmaken van tien acties en ze dan toewijzen aan Python-scripts Comment[pl]=Wtyczka oparta na Pythonie do tworzenia działań i przypisywanie ich skryptom Pythona Comment[pt]=Um 'plugin' feito em Python para criar dez acções e atribuí-las a programas em Python Comment[sv]=Ett Python-baserat insticksprogram för att skapa tio åtgärder och tilldela dem till Python-skript Comment[uk]=Скрипт на основі Python для створення десяти дій і прив'язування до них скриптів Python Comment[x-test]=xxA Python-based plugin for creating ten actions and assign them to Python scriptsxx -Comment[zh_CN]=基于 Python 的可创建十个操作并将它们指定到其它 Python 脚本的插件 +Comment[zh_CN]=基于 Python 的用于创建十个操作并将它们指定到特定 Python 脚本的插件 Comment[zh_TW]=基於 Python 的外掛程式,用於建立 10 個動作並且將它們指定給 Python 腳本