From 887b4a7a1a7d27d6c5bf12024e730fa06b2ab03e Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 7 Feb 2019 23:13:47 +0100 Subject: [PATCH] Start working on a simple Launcher app. Let GButton have an optional icon (GraphicsBitmap) that gets rendered in the middle of the button if present. Also add GraphicsBitmap::load_from_file() which allows mmap'ed RGBA32 files. I wrote a little program to take "raw" files from GIMP and swizzle them into the correct byte order. --- Base/res/icons/FontEditor.png | Bin 0 -> 500 bytes Base/res/icons/FontEditor.rgb | Bin 0 -> 4096 bytes Base/res/icons/Terminal.png | Bin 0 -> 980 bytes Base/res/icons/Terminal.rgb | Bin 0 -> 4096 bytes Base/res/icons/file.png | Bin 0 -> 405 bytes Base/res/icons/file.rgb | Bin 0 -> 4096 bytes Base/res/icons/folder.png | Bin 0 -> 1106 bytes Base/res/icons/folder.rgb | Bin 0 -> 4096 bytes Base/res/icons/generic.png | Bin 0 -> 1538 bytes Base/res/icons/generic.rgb | Bin 0 -> 4096 bytes Kernel/init.cpp | 6 ++- Kernel/makeall.sh | 2 + Kernel/makeuserland.sh | 2 + Kernel/sync.sh | 1 + Launcher/.gitignore | 3 ++ Launcher/Launcher | Bin 0 -> 62276 bytes Launcher/Makefile | 34 +++++++++++++ Launcher/main.cpp | 79 ++++++++++++++++++++++++++++++ LibGUI/GButton.cpp | 18 +++++-- LibGUI/GButton.h | 6 +++ SharedGraphics/Color.h | 17 +++++-- SharedGraphics/GraphicsBitmap.cpp | 57 ++++++++++++++++++++- SharedGraphics/GraphicsBitmap.h | 6 +++ SharedGraphics/Painter.cpp | 28 +++++++++++ SharedGraphics/Painter.h | 1 + SharedGraphics/Point.h | 7 +++ SharedGraphics/Size.h | 2 + Userland/guitest2.cpp | 2 +- Utilities/convert-raw-to-rgb.cpp | 33 +++++++++++++ 29 files changed, 293 insertions(+), 11 deletions(-) create mode 100644 Base/res/icons/FontEditor.png create mode 100644 Base/res/icons/FontEditor.rgb create mode 100644 Base/res/icons/Terminal.png create mode 100644 Base/res/icons/Terminal.rgb create mode 100644 Base/res/icons/file.png create mode 100644 Base/res/icons/file.rgb create mode 100644 Base/res/icons/folder.png create mode 100644 Base/res/icons/folder.rgb create mode 100644 Base/res/icons/generic.png create mode 100644 Base/res/icons/generic.rgb create mode 100644 Launcher/.gitignore create mode 100755 Launcher/Launcher create mode 100644 Launcher/Makefile create mode 100644 Launcher/main.cpp create mode 100644 Utilities/convert-raw-to-rgb.cpp diff --git a/Base/res/icons/FontEditor.png b/Base/res/icons/FontEditor.png new file mode 100644 index 0000000000000000000000000000000000000000..0ee4ffbde50fdd1824347cb338b0488e23b309a4 GIT binary patch literal 500 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}EX7WqAsieW95oy%9SjT% z@l_!aB|(Yh3I#>^X_+~x3MG{VsS1t(0fr0=95Ww#`JeUHJ>?Uop>fLp^cl~mK@7~v z!g|8q!rqHrn3CmvkcL=$iO;7YDVNN$=Q;#m<>D5vod&W6FF&h z#o35~fziR!#W5tJ^=+7U-ys8@+Lb#F&S^Fc%D=3f(jT#5w&?PgqHeQ9g|<6n_!$VL z84DiVIG2BB7pwoOTWaqKJj00 zjmQ=+Iqmh%U{cx9OZ6Q}Yi?BYMovGsahij-vHknAPd_X^o?3mZN^OV#p(?eQZRtNQ zGH)K#Wy4GvV%T8^SuRT=%!^*;Mi^q}tJu-RHed(7Ku1~zmz`(%Z>FVdQ&MBb@ E0L3}UBLDyZ literal 0 HcmV?d00001 diff --git a/Base/res/icons/FontEditor.rgb b/Base/res/icons/FontEditor.rgb new file mode 100644 index 0000000000000000000000000000000000000000..6a8ecfa6b67475c964f5566d9525030a2b543ac2 GIT binary patch literal 4096 zcmZP=1%o97{xdKzfG{ri;FH6phgflt*~l1OA50D;j?4z}v0+?lK;qccgTz2`Fbv|u zFiZ?YgTz2I41@UCFgE%BiHV8W#F6#Gwh6axk&~Gp~O9-+Au+|GJZJ|NCrt_FuAbGrAg>S`ZDB zL#9FE=op(kRxuLo2ib$o9FRCNMpgr2gXBOo41@R}{NMD?|NjgxUjJwK{qH}+x{d!C zdi&AUfYiY-Ob(fb$)VH8YLMB;>PWF4-3)X-vbiuevKkN@CJv*CwI8GxhGBX^G)xRc zgZSteB#w+ReELD=;gUxd2eCnF(J?Xp2k8Z2biL?&kQxw%iG$e47$%NP6JtNJ zdScng_JY{B^wGn9Ty}%RiM1c(2V59r4l+hohb)ebO^p4>=3!%_n~SUlT@Ia3ZTm^F z8{`&Z><6hs$1r^X_+~x3MG{VsS1t(0fr0=95Ww#`JeUHJ>?Uop>fLp^cl~mK@7~v z!g|8q!rqHrn3CmvkcL=$iO;7YDVNN$=Q;#m<>D5vod&W6FF&h z#o35~fmy-R#W5tJ_3iY;Eah;4mi?>b)F*6cbcoPbvuu68LC4~xV2#C79=o6fMQM(f zqZ^f9zwLize$9>TrT-iI-#r&RKAXe_$A;Rr>A!BB{_Nn_uU{+99h!aCjp4LTU1{mp zIbRu%rER{r>HpcYXU}d9*|%p;O#k%%^X~lFcJg4H^QknBo{0`(PLD#-aAF^BY*+9Ah|Awmr2+Rz5#}$ifea=pc z`m@))KVCjsDWX^2ShrkP&0YL*U6`@Zgb2o}E^f8E_WLS*J!9tlXXrbs6BW_Gb5^uqQG1!@EP5wsF)!P@#@*ljp|M|NaopwWZ@&tJ)-u=X`n&nD23-EEyv6UM;xUi@mpU`bpBY`_ zIAPd&lW)RFRqmG`CO&33FrztDr7T$4I^9xfw{2~yPj%m`RgW2@T-O}Fms7rMrW?OROK9%Nl;+BwhY|NzFAZPT z$GF06wWb?$@sYG3#hI_Z?U_bmo5y_43R7#q& z&P8iS9Xu0R5G7!GG|ew&tAzD!*S3KCh^q5eOP0O8b?m9nnW9n?dBzW?*W1gRy{eCy q&v>Igs&?JiNB?KkMC$LeW3<|kvoUM+8GQx@1_n=8KbLh*2~7akAGs3% literal 0 HcmV?d00001 diff --git a/Base/res/icons/Terminal.rgb b/Base/res/icons/Terminal.rgb new file mode 100644 index 0000000000000000000000000000000000000000..ea24005df56d4b8b542fe8ff8122ee358f9e821c GIT binary patch literal 4096 zcmZP=1%o04;^N}|(-R|m8f5Rvl`H?#6NBu8xdFrm*$txUfhSI!2o7s(_A@Xt{0CzO zhW`vu%*4d}pNX02KMOOC3y$IJVl4`eq#$ZmoELPA3SMMOpZi;0Q+7nczK zFDW5Ol>H!o|NH;{KNBO&UwM<98$Ij z{udDz0b_A7nB9nUE+;GZUtU4(zoG)j--`cLRFwa#si_gPA5^};(i#^x$lpBw!C}q^ zDqHye3xLv^kkEf&5uyL0!Xn^u4HVy!5+J)l{+9g@vRh7G;lF}B$ZjRD-Kwf;|J5}# z2-?ri0m@?_e?!VtNIK{J&j-rm@c0ImEh7I#MMeKhh)evJ5SRQfEiL(92Aan}>0C)s z5ggxOe}n8+Q~R%}sY%d&P7cohpmL3en;YzJUS3{sc`hg@04~dggkfci7`RN80Qp-= z^1rN%^nY17S+JiK6%_v~DJuO}QBnbixrT=Ne@!jT|JvGG1nmchUq)8uzl@yRe>nyD|BCV;e=Gi1Q3l1g>VFM& zwf`DgTK{#lwf<}CXcM%biyKszaR2Ay0hKKR|M>+$WttGUTm#uH3QFgoG8N=+X{rA* zGSdHLWI_Ix`>y~>Yl_PMm6cWhL*iTgzlMg^e=TjT|GK(5|Mm3r2-**?O9TX0=<5F0)6@NL zXlO{3{rvoV{{;j=c^s6#L3WG&2j?*fNLrHwmFLpZ|K&mPEhqn95oA9oe=9@mR#R91 zuc4{=UrSs2zqXFxeO?-A$BV%DgIYcg`_n#bxejg5@{o0*ytv|mU7Qhy7B>u<6D;$q_eB|vQlX{rCR;QTEMj&D$1qO7d=Us)BJ z*3{JhYl8g^No)FgdjAa!4E`G%8UHsnHvVsBYWCmU!h)dv1KIurwF~KmLH>lbe?c^e OPfrZ8a}*DJ2mk^X_+~x3MG{VsS1t(0fr0=95Ww#`JeUHJ>?Uop>fLp^cl~mK@7~v z!g|8q!rqHrn3CmvkcL=$iO;7YDVNN$=Q;#m<>D5vod&W6FF&h z#o35~f#IR2i(^Pc>)Yv$d`%8KuJxVSz9tu&3puCBw5m>jkdQRx0OK0&2^x&g#XE9- znVk`MQS<9I53_}|^0DWoZ-0m}u38nqFp(qVaFmP6j$`LGS%_$?ZmVf+7Q9gZ^X

GB?g|BkEVUVoi~(V$=Z-r|pN(qkW<62C z+Z$;hW8AXKVP@8R9={St6YF1I0l6na{(RUMeIRMmgR>#0Ca?Li%V-B{8h6{v_+8>V zShuk5*Q(EXC${0tJ#MGF55zX)=rvf1>-^;2B3Co#|7RxK-fa`~Jvt;97#J8lUHx3v IIVCg!0LNyT>;M1& literal 0 HcmV?d00001 diff --git a/Base/res/icons/file.rgb b/Base/res/icons/file.rgb new file mode 100644 index 0000000000000000000000000000000000000000..7c71465d85dd126315fac4c64a7e940432a540af GIT binary patch literal 4096 zcmZP=1w$zW{xdKzkb3^`@AKpRy4R*^vy2d}) zuh4KrVZ*{3ka D8XZ%e literal 0 HcmV?d00001 diff --git a/Base/res/icons/folder.png b/Base/res/icons/folder.png new file mode 100644 index 0000000000000000000000000000000000000000..3be71f1b4f8ad61360fe0e6be0950fd92716ac92 GIT binary patch literal 1106 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}EX7WqAsieW95oy%9SjT% z@l_!aB|(Yh3I#>^X_+~x3MG{VsS1t(0fr0=95Ww#`JeUHJ>?Uop>fLp^cl~mK@7~v z!g|8q!rqHrn3CmvkcL=$iO;7YDVNN$=Q;#m<>D5vod&W6FF&h z#o35~fq9;%i(^Pc>)YwJeKD>gt^2Er@~$~P>*)w>kloCr66VNI?O?>Xnb)Ohg6_u2 zjZ>_i3*3qRdhg5@Ri=IcAydcw?^dp>e)Z?hs{QW0;@jPCKeHCAY8j@Rj z4o*CH_xJB~){SE4UWemTaCX3I6+PKfk>7`Q(8~>JE?Q#jIaA&r|n}M6yw{QpyLW?Gcg1 zxjKS}a<0j|U&U|Bu(kL)-@+ID*^DDy8YMw{qrA(!o-qyGA3B=66beo z()o3L(X#S|Rnu0T_;e(MajU!U;TcqcNE;yqq&6;$8S53UYZ-3S1r1l+4 zrrgm9xU@8)hUq~;=Z2m%(Y;$(jxwn_&OXO`N|XQ0wd-PnXGAoX&-lQ@sbS8b!{#?D zYh%~L3}>^cA5P@BH6+bg`g_Z^e_LOFn^+UwbTw^j?{&6UI>)oz*Tf9x^%lPU6(koxyCrcP45ZOuDt;Cc}2kxqZv5U6-Gn?{&ekBz>pD zl||ZCpC+w%5%)!{(ZqS#%Y3zzO;xVvPwMjbq%FObW~?Z<&Y^1h7SGyc33<)es+ae4 z`QLinu;Xq=M#$5Q(v(vZigZ`ZdEOZHKKGjUF>~wOv}^CgcTYF|X!3BeltyNh0? z{9xvpBlqFlw?!9fg|b{<>npxEe4^HB-u+0~Dc`&<{aa90e{a4V!wSEYxnI;BH}~I~ z!nxEear4B}6Zg#alV2#kXRrUwuFtw`QdhT}dfRBJfA;Wmzw&#Am-lYg+m>XOyeKc@ zbnr^yZ)(ielC{kz<2w4}*H&BB#ob!HoAc<+XWh*omf7$<+mmg>W^nIc+5GMC_5Th$ zd}R|}V-?r5lZ$y~y36)-mSYcgZP2PM^zCr>EZNx>cYJNU+j+xzU$0-Q&;G+(5_dRx U?PR&f3=9kmp00i_>zopr00N`@wEzGB literal 0 HcmV?d00001 diff --git a/Base/res/icons/folder.rgb b/Base/res/icons/folder.rgb new file mode 100644 index 0000000000000000000000000000000000000000..fb5db9134911e51dbb58e0cedab5d325681285d0 GIT binary patch literal 4096 zcmZP=1%oLB{xdKzpksQu??1m`2pIDjh5hF@4*f4+6b^F>t=;gS-!SYypHb+40Yj+W z#-acDLGCb$fVqKE8lNBj^Bac#=QD)bX&m-nzzF1?u>br<;s5!KBmWDSMEn;pjsjzT zlc@jvCei-|Or!q`n#TMWFpd2$0H$O93!26K7ch(aFKCwVU%)&biW6XN$K{6q{2;#@ zg@VHY6z=@Spl}HPFJKJ95W7M43YbLw2Vs8G=>GyHF<|@oVRnPu0k%K>zaY$Ri-iAz z7770aEE4g#0UXu>#$o^YjKg5+Xi1}o1H}Kvkn|Sbd+2{y_o4s6od^C0cI^Kj*uM9F zK=bbZ{>?l7`!sC(?^VC$zeml+|L)c6|GQPJ`R`J;`oB}j^8fZlOaI&EFaB?xJO96B z*1Z4bnX~?zrA_~DoHFIVQPQOUdU5^#^<(;A{z7)ce~{lnc`vNz$p28N-N7CE{s*@1 z`S0Jd>%V`~j{m+5TmO64Z~gBHvb$>if7i-2|6NK!cCY;JP_*p7ZQi2));SCQTV~Jw zZ;>(kzj^BP|0XF@{u?Jv{;wb3|6eb*@4t3b&ws7(4sf z&;P)d-T(btcK-Km*ao)St9BFE->y|_!FD^AtoZL(wDiAS{^I{OxeNbWf$g64-z8<+}ea<*WZYm#+BlSiJPVZNZ}dHhCbs=l!?Ln)BZ*ZN`6- zl&N5U8^%xkuNMQdyZgUZWaod4u=fAzAuX8pL-TnMD9+mucKbH$0Q(zcHz>Z{E7tvY zEnoBBv25jk$KvJx?Ftq{?FPj;$nKe7yN!}2|2K@E@LxZ!|G!QQ$nK8+n&A+;Rf3x^ z?Kgq=Kd58h|A5xr|NUAZ{`RWd`X3bLp4A)wyH>6T``f7u;&1zcCI4;n7W}u$p8ww> zbIyPB^jZH+)24y_ZIl2C_x}I7(LMjQBfI`IiLZ{jV0(^j|fw@xPLPE!Zxk3;-_QKKY*2j9{coND%V(4S8zoEzr#BtA zzae(31~>m#32OYWk}8%rtezf8*pS{|ysC`E0^}z1SXbTGxyK#d+(0b&%Zw_5YRp>;5bFR{dA- zsRY}F?0-<%3i3a=e5nJ4`=FlDO3N0(z<@a#Q(anP`g3#4YnH;-wpqjKz{dw*e&Z- z{$Iwk4AXv7NcelyZv5{7E?3w6cP?G?-?0>w-j;#O7u%eL|E;n>`D`{kkAuopgZPR6 z^<#Vg>qK?`*N*7=5AwHKNDCys{Tu!(_*MT`^sV|Y=T-4v*1i0{lv@dg{jl)&s9FEt zwPNjm=W;~33d`fx;Pf^dT(*JA7o+4!{|yr%Wg9r3MRfev2ygqZ7SjA*HK_5wazOom zMZenr3O?2U<-9BY%X*gmmvJlpFXdWtP zU*4e6j`Q4@Hzm!Yie{skB|6-1LV7rj>pP+dxSj?#y6y{4IVV=9-za_X_ zoeeHmO_HbnH%x%!Gf-OB0ofhV@n1cp^}lLR(|;9EI`^;rujp6(U%?xa-oSRdLhP1s zF8D9*ko#ZEJ_l?Uvi$<)abPj~!o}cn)h2hre=CsP86dksZHTG=;bnSE?|+?0NS&e) z*79FH1RCf5wf_~sdA#bstXCO0&ZS*T{!6+Pg2PqL+*bO`)sgXDE6B|{BM`H z_`h`yD35{4m)ZZ#)2IJ8NuKuKIC1iSgE&YY*8#O5BHI6}gW@|BlGc^{>;EhI*8G?E z1=(HkU&f>Kzm$6sIIW307yK7<$ontmkn>;IKKsA0T^73iAg6%yxJ}-I|CU*h_KR66 zq8>L$0F|qd@�ng7TR^X_+~x3MG{VsS1t(0fr0=95Ww#`JeUHJ>?Uop>fLp^cl~mK@7~v z!g|8q!rqHrn3CmvkcL=$iO;7YDVNN$=Q;#m<>D5vod&W6FF&h z#o35~fz{8`#W5tJ_3gCGoRCnFgx`B{8B6pyVi zbcqobo_>UbldB`pZbkx!2n%blz@3E)bb^>Ox|u_FC9b|8mXW>CX}PuW-10vLYjfMr zIY=k{IbdIT()(TQ_y5+oxf?wK#Ww?39zgW(fj^ndT-wfFuipO1)B z|MmCQ{!8zt}#uut@F|NI5HS78fxrzv+i`i*0*&_cVy1@-ho&wJJH6_9M#{X%dY@C` zwktLXEk2~SX3x#z(>{rrz13TEZ!^2>(?!#O2SQ=jFbzyy3vH!@Ya#|KzTUnm$`RP_A z^nkzBpsnMNa&GS|^<_5~o3QQktFzuA?(V}Btghn9a)B$)v-jCTYxR$jTlwd2(-!2^ zI9y;<`_FvTynF#s8u5@ z`*xFn!{+xX(=`rXDB80lV%q)P92tyNhZr*su%=v!NL2j&FDG@Q^ySNUHWhqJ2`%%} z_`SB}kMGYXwHv$bt$FSgaxOW_ANz{ak9)Pv*;6*#wufD_-OHT8a*jcqE$!hVT?H$< zX}?Zotke$F`rTM~{{Fm#JyV3;Lu$CJ{Yw_U(X-mM%kt6BR^FepZwA-RdTq4Xqr03Z z>O}5ko!E`b=IO3~$KGv|r+^{^GgCe49V7-*@nhi*>7ikFx1G-gkj3T1u|Wm_4K5 zdhMNZ=la$e%QRnKU%#Hg>*Y%;z7oDvIZvqqCQE7iv;VEOh|Yh_b>i8nvdZVrKYvP& zUH+xzPOEm<8jF@7??%st-iLq6c_y%W=xb<1XetH8#l`JU{av1JUDLSXKXYnoYI^$F zS)n|ygdYehO!SU9Iq?Kfg2@DK8;%r)jpvRSZhZWF->fMUEj@4Nm=)gU2@T$}du`hH zW5;IAlG0z{HNokDLV?r=Ll^FSG7P*&7|j{CGkw&U+H|7SCEj@2?DYOXv)$7!r>+fo zzn)ntV3o*3r3F(G?v}e6z3(=f#N;4dz_o&D)dq{G7vFwaMqWBKBU*M!%~M93jJ@m= zYaLh%rcG!wp2YK|_w_w@L7RZ<7v@imc);?2@gK_`7U|wf%V*P>1+2muuf;vy$g+I} zqlIVv-1uo9Js8;P7B^}f;4ArVcX-uj?S*y|1h4-1@AjV|%WEf3i|s@|1_lNOPgg&e IbxsLQ04f5^b^rhX literal 0 HcmV?d00001 diff --git a/Base/res/icons/generic.rgb b/Base/res/icons/generic.rgb new file mode 100644 index 0000000000000000000000000000000000000000..ba39a5eb0e85582acd72c0dcb8325acd887c8255 GIT binary patch literal 4096 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 +#include +#include +#include +#include +#include +#include + +static GWindow* make_launcher_window(); + +void handle_sigchld(int) +{ + dbgprintf("Launcher(%d) Got SIGCHLD\n", getpid()); + int pid = waitpid(-1, nullptr, 0); + dbgprintf("Launcher(%d) waitpid() returned %d\n", getpid(), pid); + ASSERT(pid > 0); +} + +int main(int, char**) +{ + signal(SIGCHLD, handle_sigchld); + + GEventLoop loop; + + auto* launcher_window = make_launcher_window(); + launcher_window->set_should_exit_app_on_close(true); + launcher_window->show(); + + return loop.exec(); +} + +GWindow* make_launcher_window() +{ + auto* window = new GWindow; + window->set_title("Launcher"); + window->set_rect({ 50, 50, 300, 60 }); + + auto* widget = new GWidget; + window->set_main_widget(widget); + widget->set_relative_rect({ 0, 0, 300, 60 }); + + auto* terminal_button = new GButton(widget); + terminal_button->set_relative_rect({ 5, 5, 50, 50 }); + terminal_button->set_icon(GraphicsBitmap::load_from_file("/res/icons/Terminal.rgb", { 32, 32 })); + + terminal_button->on_click = [] (GButton&) { + pid_t child_pid = fork(); + if (!child_pid) { + execve("/bin/Terminal", nullptr, nullptr); + ASSERT_NOT_REACHED(); + } + }; + + auto* font_editor_button = new GButton(widget); + font_editor_button->set_relative_rect({ 60, 5, 50, 50 }); + font_editor_button->set_icon(GraphicsBitmap::load_from_file("/res/icons/FontEditor.rgb", { 32, 32 })); + + font_editor_button->on_click = [] (GButton&) { + pid_t child_pid = fork(); + if (!child_pid) { + execve("/bin/FontEditor", nullptr, nullptr); + ASSERT_NOT_REACHED(); + } + }; + + auto* guitest_editor_button = new GButton(widget); + guitest_editor_button->set_relative_rect({ 115, 5, 50, 50 }); + guitest_editor_button->set_icon(GraphicsBitmap::load_from_file("/res/icons/generic.rgb", { 32, 32 })); + + guitest_editor_button->on_click = [] (GButton&) { + pid_t child_pid = fork(); + if (!child_pid) { + execve("/bin/guitest", nullptr, nullptr); + ASSERT_NOT_REACHED(); + } + }; + + return window; +} diff --git a/LibGUI/GButton.cpp b/LibGUI/GButton.cpp index b94a863f75..2309ee0be0 100644 --- a/LibGUI/GButton.cpp +++ b/LibGUI/GButton.cpp @@ -55,11 +55,19 @@ void GButton::paint_event(GPaintEvent&) painter.draw_line({ 2, height() - 3 }, { width() - 2, height() - 3 }, shadow_color); } - if (!caption().is_empty()) { - auto text_rect = rect(); - if (m_being_pressed) - text_rect.move_by(1, 1); - painter.draw_text(text_rect, caption(), Painter::TextAlignment::Center, Color::Black); + if (!caption().is_empty() || m_icon) { + auto content_rect = rect(); + auto icon_location = m_icon ? content_rect.center().translated(-(m_icon->width() / 2), -(m_icon->height() / 2)) : Point(); + if (m_being_pressed) { + content_rect.move_by(1, 1); + icon_location.move_by(1, 1); + } + if (m_icon) { + painter.blit_with_alpha(icon_location, *m_icon, m_icon->rect()); + painter.draw_text(content_rect, caption(), Painter::TextAlignment::Center, Color::Black); + } else { + painter.draw_text(content_rect, caption(), Painter::TextAlignment::Center, Color::Black); + } } } diff --git a/LibGUI/GButton.h b/LibGUI/GButton.h index b5164ca26e..6c40d84401 100644 --- a/LibGUI/GButton.h +++ b/LibGUI/GButton.h @@ -3,6 +3,7 @@ #include "GWidget.h" #include #include +#include class GButton final : public GWidget { public: @@ -12,6 +13,10 @@ public: String caption() const { return m_caption; } void set_caption(String&&); + void set_icon(RetainPtr&& icon) { m_icon = move(icon); } + const GraphicsBitmap* icon() const { return m_icon.ptr(); } + GraphicsBitmap* icon() { return m_icon.ptr(); } + Function on_click; private: @@ -23,6 +28,7 @@ private: virtual const char* class_name() const override { return "GButton"; } String m_caption; + RetainPtr m_icon; bool m_being_pressed { false }; bool m_tracking_cursor { false }; }; diff --git a/SharedGraphics/Color.h b/SharedGraphics/Color.h index b38ecbb5ab..934e6bdd13 100644 --- a/SharedGraphics/Color.h +++ b/SharedGraphics/Color.h @@ -29,9 +29,20 @@ public: Color(byte r, byte g, byte b) : m_value((r << 16) | (g << 8) | b) { } Color(RGBA32 rgba) : m_value(rgba) { } - int red() const { return (m_value >> 16) & 0xff; } - int green() const { return (m_value >> 8) & 0xff; } - int blue() const { return m_value & 0xff; } + byte red() const { return (m_value >> 16) & 0xff; } + byte green() const { return (m_value >> 8) & 0xff; } + byte blue() const { return m_value & 0xff; } + byte alpha() const { return (m_value >> 24) & 0xff; } + + Color blend(Color source) const + { + RGBA32 redblue1 = ((0x100u - source.alpha()) * (m_value & 0xff00ff)) >> 8; + RGBA32 redblue2 = (source.alpha() * (source.m_value & 0xff00ff)) >> 8; + RGBA32 green1 = ((0x100u - source.alpha()) * (m_value & 0x00ff00)) >> 8; + RGBA32 green2 = (source.alpha() * (source.m_value & 0x00ff00)) >> 8; + return Color(((redblue1 | redblue2) & 0xff00ff) + ((green1 | green2) & 0x00ff00)); + } + RGBA32 value() const { return m_value; } diff --git a/SharedGraphics/GraphicsBitmap.cpp b/SharedGraphics/GraphicsBitmap.cpp index 8c8b6c0949..d812218cfe 100644 --- a/SharedGraphics/GraphicsBitmap.cpp +++ b/SharedGraphics/GraphicsBitmap.cpp @@ -1,5 +1,4 @@ #include "GraphicsBitmap.h" -#include #ifdef KERNEL #include @@ -7,6 +6,14 @@ #include #endif +#ifdef USERLAND +#include +#include +#include +#include +#include +#endif + #ifdef KERNEL RetainPtr GraphicsBitmap::create(Process& process, const Size& size) { @@ -39,6 +46,49 @@ RetainPtr GraphicsBitmap::create_wrapper(const Size& size, RGBA3 return adopt(*new GraphicsBitmap(size, data)); } +RetainPtr GraphicsBitmap::load_from_file(const String& path, const Size& size) +{ +#ifdef USERLAND + int fd = open(path.characters(), O_RDONLY, 0644); + if (fd < 0) { + dbgprintf("open(%s) got fd=%d, failed: %s\n", path.characters(), fd, strerror(errno)); + perror("open"); + return nullptr; + } + + auto* mapped_file = (RGBA32*)mmap(nullptr, size.area() * 4, PROT_READ, MAP_SHARED, fd, 0); + if (mapped_file == MAP_FAILED) { + int rc = close(fd); + ASSERT(rc == 0); + return nullptr; + } +#else + int error; + auto descriptor = VFS::the().open(path, error, 0, 0, *VFS::the().root_inode()); + if (!descriptor) { + kprintf("Failed to load GraphicsBitmap from file (%s)\n", path.characters()); + ASSERT_NOT_REACHED(); + } + auto* region = current->allocate_file_backed_region(LinearAddress(), size.area() * 4, descriptor->inode(), ".rgb file", /*readable*/true, /*writable*/false); + region->page_in(); + auto* mapped_file = (RGBA32*)region->laddr().get(); +#endif + + +#ifdef USERLAND + int rc = close(fd); + ASSERT(rc == 0); +#endif + auto bitmap = create_wrapper(size, mapped_file); +#ifdef KERNEL + bitmap->m_server_region = region; +#else + bitmap->m_mmaped = true; +#endif + + return bitmap; +} + GraphicsBitmap::GraphicsBitmap(const Size& size, RGBA32* data) : m_size(size) , m_data(data) @@ -53,6 +103,11 @@ GraphicsBitmap::~GraphicsBitmap() m_client_process->deallocate_region(*m_client_region); if (m_server_region) WSMessageLoop::the().server_process().deallocate_region(*m_server_region); +#else + if (m_mmaped) { + int rc = munmap(m_data, m_size.area() * 4); + ASSERT(rc == 0); + } #endif m_data = nullptr; } diff --git a/SharedGraphics/GraphicsBitmap.h b/SharedGraphics/GraphicsBitmap.h index de3f934ad2..861e0d4170 100644 --- a/SharedGraphics/GraphicsBitmap.h +++ b/SharedGraphics/GraphicsBitmap.h @@ -5,6 +5,7 @@ #include "Size.h" #include #include +#include #ifdef KERNEL #include "Process.h" @@ -16,6 +17,7 @@ public: static RetainPtr create(Process&, const Size&); #endif static RetainPtr create_wrapper(const Size&, RGBA32*); + static RetainPtr load_from_file(const String& path, const Size&); ~GraphicsBitmap(); RGBA32* scanline(int y); @@ -42,6 +44,10 @@ private: RGBA32* m_data { nullptr }; size_t m_pitch { 0 }; +#ifdef USERLAND + bool m_mmaped { false }; +#endif + #ifdef KERNEL WeakPtr m_client_process; Region* m_client_region { nullptr }; diff --git a/SharedGraphics/Painter.cpp b/SharedGraphics/Painter.cpp index 486352a958..8f7ead9c21 100644 --- a/SharedGraphics/Painter.cpp +++ b/SharedGraphics/Painter.cpp @@ -368,6 +368,7 @@ void Painter::draw_focus_rect(const Rect& rect) void Painter::blit(const Point& position, const GraphicsBitmap& source, const Rect& src_rect) { Rect dst_rect(position, src_rect.size()); + dst_rect.move_by(m_translation); dst_rect.intersect(m_clip_rect); RGBA32* dst = m_target->scanline(dst_rect.y()) + dst_rect.x(); @@ -383,6 +384,33 @@ void Painter::blit(const Point& position, const GraphicsBitmap& source, const Re } } +void Painter::blit_with_alpha(const Point& position, const GraphicsBitmap& source, const Rect& src_rect) +{ + Rect dst_rect(position, src_rect.size()); + dst_rect.move_by(m_translation); + dst_rect.intersect(m_clip_rect); + + RGBA32* dst = m_target->scanline(dst_rect.y()) + dst_rect.x(); + const RGBA32* src = source.scanline(src_rect.top()) + src_rect.left(); + + const unsigned dst_skip = m_target->width(); + const unsigned src_skip = source.width(); + + for (int i = dst_rect.height() - 1; i >= 0; --i) { + for (int x = 0; x < dst_rect.width(); ++x) { + byte alpha = Color(src[x]).alpha(); + if (alpha == 0xff) + dst[x] = src[x]; + else if (!alpha) + continue; + else + dst[x] = Color(dst[x]).blend(src[x]).value(); + } + dst += dst_skip; + src += src_skip; + } +} + void Painter::set_clip_rect(const Rect& rect) { m_clip_rect = Rect::intersection(rect, m_target->rect()); diff --git a/SharedGraphics/Painter.h b/SharedGraphics/Painter.h index dd9b807f2b..eef0675c49 100644 --- a/SharedGraphics/Painter.h +++ b/SharedGraphics/Painter.h @@ -32,6 +32,7 @@ public: void draw_line(const Point&, const Point&, Color); void draw_focus_rect(const Rect&); void blit(const Point&, const GraphicsBitmap&, const Rect& src_rect); + void blit_with_alpha(const Point&, const GraphicsBitmap&, const Rect& src_rect); enum class TextAlignment { TopLeft, CenterLeft, Center, CenterRight }; void draw_text(const Rect&, const String&, TextAlignment = TextAlignment::TopLeft, Color = Color()); diff --git a/SharedGraphics/Point.h b/SharedGraphics/Point.h index 222eddcb46..a0c0e3a4aa 100644 --- a/SharedGraphics/Point.h +++ b/SharedGraphics/Point.h @@ -26,6 +26,13 @@ public: move_by(delta.x(), delta.y()); } + Point translated(int dx, int dy) + { + Point point = *this; + point.move_by(dx, dy); + return point; + } + void constrain(const Rect&); bool operator==(const Point& other) const diff --git a/SharedGraphics/Size.h b/SharedGraphics/Size.h index 4e5a4ea811..87f2c5b088 100644 --- a/SharedGraphics/Size.h +++ b/SharedGraphics/Size.h @@ -13,6 +13,8 @@ public: int width() const { return m_width; } int height() const { return m_height; } + int area() const { return width() * height(); } + void set_width(int w) { m_width = w; } void set_height(int h) { m_height = h; } diff --git a/Userland/guitest2.cpp b/Userland/guitest2.cpp index 54187c82a6..45e7759df3 100644 --- a/Userland/guitest2.cpp +++ b/Userland/guitest2.cpp @@ -78,7 +78,7 @@ GWindow* make_font_test_window() GWindow* make_launcher_window() { auto* window = new GWindow; - window->set_title("Launcher"); + window->set_title("guitest2"); window->set_rect({ 100, 400, 100, 230 }); auto* widget = new GWidget; diff --git a/Utilities/convert-raw-to-rgb.cpp b/Utilities/convert-raw-to-rgb.cpp new file mode 100644 index 0000000000..15e9868233 --- /dev/null +++ b/Utilities/convert-raw-to-rgb.cpp @@ -0,0 +1,33 @@ +#include +#include +#include +#include + +int main(int argc, char**argv) +{ + int fd = open(argv[1], O_RDONLY); + if (fd < 0) { + perror("open"); + return 1; + } + for (;;) { + unsigned buffer; + ssize_t nread = read(fd, &buffer, sizeof(buffer)); + if (nread == 0) + break; + if (nread < 0) { + perror("read"); + return 1; + } + unsigned converted = buffer & 0xff00ff00; + converted |= (buffer & 0xff0000) >> 16; + converted |= (buffer & 0xff) << 16; + write(1, &converted, sizeof(unsigned)); + } + int rc = close(fd); + if (rc < 0) { + perror("close"); + return 1; + } + return 0; +}