From 21404d958ef7d78727c6984d87dddc9b128e538c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robin=20=E2=9D=A4=EF=B8=8F?= Date: Wed, 15 Oct 2025 13:28:38 -0400 Subject: [PATCH] [examples] Added `core_clipboard_text` (#5231) * added clipboard example * added image check * added note about windows * added indent --- examples/core/core_clipboard_text.c | 208 ++++++++++++++++++++++++++ examples/core/core_clipboard_text.png | Bin 0 -> 15878 bytes 2 files changed, 208 insertions(+) create mode 100644 examples/core/core_clipboard_text.c create mode 100644 examples/core/core_clipboard_text.png diff --git a/examples/core/core_clipboard_text.c b/examples/core/core_clipboard_text.c new file mode 100644 index 000000000..973163cb5 --- /dev/null +++ b/examples/core/core_clipboard_text.c @@ -0,0 +1,208 @@ +/******************************************************************************************* +* +* raylib [core] example - clipboard text +* +* Example complexity rating: [★☆☆☆] 1/4 +* +* Example originally created with raylib 5.6-dev +* +* Example contributed by Robin (@RobinsAviary) and reviewed by Ramon Santamaria (@raysan5) +* +* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, +* BSD-like license that allows static linking with closed source software +* +* Copyright (c) 2025-2025 Robin (@RobinsAviary) +* +********************************************************************************************/ + +#include "raylib.h" + +#include + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [core] example - clipboard text"); + + const char* clipboardText = NULL; + + // List of text the user can switch through and copy + const char* copyableText[] = {"raylib is fun", "hello, clipboard!", "potato chips"}; + + unsigned int textIndex = 0; + + const char* popupText = NULL; + + // Initialize timers + // The amount of time the pop-up text is on screen, before fading + const float maxTime = 3.0f; + float textTimer = 0.0f; + // The length of time text is offset + const float animMaxTime = 0.1f; + float pasteAnim = 0.0f; + float copyAnim = 0.0f; + int copyAnimMult = 1; + float textAnim = 0.0f; + float textAlpha = 0.0f; + // Offset amount for animations + const int offsetAmount = -4; + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + // Check if the user has pressed the copy/paste key combinations + bool pastePressed = (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_V)); + bool copyPressed = (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_C)); + + // Update animation timers + if (textTimer > 0) textTimer -= GetFrameTime(); + if (pasteAnim > 0) pasteAnim -= GetFrameTime(); + if (copyAnim > 0) copyAnim -= GetFrameTime(); + if (textAnim > 0) textAnim -= GetFrameTime(); + + // React to the user pressing paste + if (pastePressed) + { + // Most operating systems hide this information until the user presses Ctrl-V on the window. + + // Check to see if the clipboard contains an image + // This function does nothing outside of Windows, as it directly calls the Windows API + Image image = GetClipboardImage(); + + if (IsImageValid(image)) + { + // Unload the image + UnloadImage(image); + // Update visuals + popupText = "clipboard contains image"; + } + else + { + // Get text from the user's clipboard + clipboardText = GetClipboardText(); + + // Update visuals + popupText = "text pasted"; + pasteAnim = animMaxTime; + } + + // Reset animation values + textTimer = maxTime; + textAnim = animMaxTime; + textAlpha = 1; + } + + // React to the user pressing copy + if (copyPressed) + { + // Set the text on the user's clipboard + SetClipboardText(copyableText[textIndex]); + + // Reset values + textTimer = maxTime; + textAnim = animMaxTime; + copyAnim = animMaxTime; + copyAnimMult = 1; + textAlpha = 1; + // Update the text that pops up at the bottom of the screen + popupText = "text copied"; + } + + // Switch to the next item in the list when the user presses up + if (IsKeyPressed(KEY_UP)) + { + // Reset animation + copyAnim = animMaxTime; + copyAnimMult = 1; + + textIndex += 1; + + if (textIndex >= sizeof(copyableText) / sizeof(const char*)) // Length of array + { + // Loop back to the other end + textIndex = 0; + } + } + + // Switch to the previous item in the list when the user presses down + if (IsKeyPressed(KEY_DOWN)) + { + // Reset animation + copyAnim = animMaxTime; + copyAnimMult = -1; + + if (textIndex == 0) + { + // Loop back to the other end + textIndex = (sizeof(copyableText) / sizeof(const char*)) - 1; // Length of array minus one + } + else + { + textIndex -= 1; + } + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + // Draw the user's pasted text, if there is any yet + if (clipboardText) + { + // Offset animation + int offset = 0; + if (pasteAnim > 0) offset = offsetAmount; + + // Draw the pasted text + DrawText("pasted clipboard:", 10, 10 + offset, 20, DARKGREEN); + DrawText(clipboardText, 10, 30 + offset, 20, DARKGRAY); + } + + // Offset animation + int textOffset = 0; + if (copyAnim > 0) textOffset = offsetAmount; + + // Draw copyable text and controls + DrawText(copyableText[textIndex], 10, 330 + (textOffset * copyAnimMult), 20, MAROON); + DrawText("up/down to change string, ctrl-c to copy, ctrl-v to paste", 10, 355, 20, DARKGRAY); + + // Alpha / Offset animation + if (textAlpha > 0) + { + // Offset animation + int offset = 0; + if (textAnim > 0) offset = offsetAmount; + // Draw pop up text + DrawText(popupText, 10, 425 + offset, 20, ColorAlpha(DARKGREEN, textAlpha)); + + // Fade-out animation + if (textTimer < 0) + { + textAlpha -= GetFrameTime(); + } + } + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/core/core_clipboard_text.png b/examples/core/core_clipboard_text.png new file mode 100644 index 0000000000000000000000000000000000000000..caa9b314a694bdb9316f9f8d07161887d53887e6 GIT binary patch literal 15878 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYU_8XZ#=yWJp1k%11B2~ZPZ!6Kin!!IzrMb% zZwoY#Vp^<-gDBx(Ty`-)j<@lmfCN^8v8wez278Lh+TOMU85})W2!oz72RGq^*d=?~ z4s76VyeK*0qKhpqXE{CC z6@%U$Pt`jkQ*>B7ykg;P_w_#(m+o26em!HR5w`fWa7rj)OEFRH!;(3-uSAs)cnlcC9Bj$lDFJC?3i88JN1W}>EGUIhM2)3#l$Sk zwAff-v1UGoU!neQ$WwIK9K4|;_HqBaV5eUv=6Whzw_Th$afg5e@BNEYusPkq2OLVv zCgTgGv+o%fewAZNa?bi9$NOuEX4d<;ir23$UY^i9Z4stJEu6uDk%~7k<}oUkuC?Fz zYUSQ^mRgm0SN5u2xp&!N-QSk9ybMwK4I&=dpFMqF9@&*%ax8m`h%81XJtzqYi())s zap1?-*Vq3axnZ_zSzW=>Qx|_o=&C|P3MIL;B|*aAHl8p5mj<|V;ssq6H*1B(ow<0N zxpT(yW#3tsD#Y z@-NxNY`es>RDarX3%0q z2Tw@qn-5P1XtfgKu2zPV#tKW`9b7Q2s^~p)W2?%><;j87{hWKhM+m(BcX6-D;-zP> zdCH;Xzzd!e8M~yh26^K}fd$bV26cabeYH2-cF^sNyT7Z{oR!5Ub#C6h*c`J^0Fs(Y z@T4Y#Ta1#vIoN#)3MbhK7fnDk_L}*RQ^N~eg~b!?aRsY^6w{Qp122TuTr|NO^lwK% z#R_U(3~=2(>V!ek$Qq4^(TD)o0E45=KbjmzljCS|gpV7HW=c>{jE2H!D8M>)qiJC@ zEsUlG95I?BMsvhyjzFKz87&t^%Z1T$VYFNrEf>H83TVV=={QMn zh*mIyxud1yXz4gwI*yi(qopIbI7A~xOUI#9I&PAkFxkqFN1;b9=*6QQS0+jyx?+}Z zvbG;NcOxR$gA1}g%MRB!~TqolQF}ND}mW*jCX5-{(9z|ne^I! z#?LQB&okmM7d3*6W(B)NZh`83$cSbNH@x^nxLqJb5&(X1wSEGvS+Yd>FzG4;gnuls8+a%lFA*%#WYZb@qXlR5hs z+mbb9$cn+>e_*F#AsFsDHKcB6`T8QR?P3UyMQexc!OISVe`3)O4ifOP!#9kQzQWkt z02XtGn(+~z8C#f*X59e$5gYMBjA^m#go{VaaODW_$~|VVb=Zi*`Ven?rN{}++n9x9 zWzRAkI?^Vx@)diul#JFp`Bx8ZE`0P`{Xu%&N28!a*(UM4@4^mdSjj}L-FESh#Vs#+ zUdB_9m9e7uR>nrOMMWG=vjr_=o#g`#f)1X>i+_w}g@8E-g3TL}m5*Z2Du}F{CU@a! z=iT{^Z%*iJ{3a}2v}9NQg1`Kq#dqz#c(_08p`S*KXDPdn?aq%5YpOGH?G(!=NXuX8 zOZWP$zV))`x&mpPhpw5NKC3@Sz4Z@(h|J1kc zSx|mEVaF2ZtoGXp-t8@EDHs0wXYF;$`stZt>HDVVVaDtV6PC7Qu*xGiKY49q+%79-TFOu3*YG{Rm$a_G+iB1;{yIot zuEJLY>MTyQm0~(<$#Nq0w)HHn0Oy7)1v0i@Q%zVeDzUg-eweXK3c68(5!@p zGFrsAIfFMH*eWb8w7^-iNHM*DxJeB|H*6vP;3%F3K?ynP1eVdX0BXF9hQeqljFyhb zwGI_>M8`bFhj|9+3=bRmnhrkV%W6OD@H2Zy+w+V>Q*5;tXe%4%wTx5P_bfp+(112! z3g5=nxB%}PYnRY`4~s@*wM)i-#re{%wAkviag4tX=3LNdIpuzW!fCMyl{i<=02v zaZ0Y(;`q*oQL*;PxhFm6VtS?tVe4Ty8-jZnm*3(FOHgks%~)Yc-$oSmGxdy(Yz+{qw%ivlr14x_wMmPnl^m+np=<_r_kZ*4etykeShO{$s9;0 zrxstJ65M47?#AKXfK|fXD7c$F#iSQ^PYT-Cyo)Cq5@_DnWN