Skip to content

Commit df414a6

Browse files
committed
GUI: Add keyboard shortcuts for copy/paste/cut in textarea widgets.
1 parent 8057a71 commit df414a6

File tree

4 files changed

+124
-28
lines changed

4 files changed

+124
-28
lines changed

plugins/gui/gui.c

+60-28
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,58 @@ char* ctr_internal_gui_copytext(char* src, uint32_t pos, uint32_t len) {
340340
return buffer;
341341
}
342342

343+
void ctr_internal_gui_copy(lv_obj_t* obj) {
344+
int issel = lv_textarea_text_is_selected(obj);
345+
if (!issel) return;
346+
lv_obj_t* txt = lv_textarea_get_label(obj);
347+
uint32_t selstart = lv_label_get_text_selection_start(txt);
348+
uint32_t selend = lv_label_get_text_selection_end(txt);
349+
char* oldbuf = lv_textarea_get_text(obj);
350+
uint32_t sellen = selend - selstart;
351+
char* selbuf;
352+
selbuf = ctr_internal_gui_copytext(oldbuf, selstart, sellen);
353+
SDL_SetClipboardText(selbuf);
354+
ctr_heap_free(selbuf);
355+
}
356+
357+
void ctr_internal_gui_paste(lv_obj_t* obj) {
358+
lv_obj_t* txt = lv_textarea_get_label(obj);
359+
uint32_t selstart = lv_label_get_text_selection_start(txt);
360+
uint32_t selend = lv_label_get_text_selection_end(txt);
361+
char* oldbuf = lv_textarea_get_text(obj);
362+
uint32_t sellen = selend - selstart;
363+
char* selbuf;
364+
int issel = lv_textarea_text_is_selected(obj);
365+
uint32_t pos = lv_textarea_get_cursor_pos(obj);
366+
if (SDL_HasClipboardText()) {
367+
if (issel) lv_label_cut_text(txt, selstart, sellen);
368+
selbuf = SDL_GetClipboardText();
369+
lv_label_ins_text(txt, pos, selbuf);
370+
if (issel) {
371+
lv_textarea_set_cursor_pos(obj, pos+sellen);
372+
lv_textarea_clear_selection(obj);
373+
}
374+
SDL_free(selbuf);
375+
}
376+
}
377+
378+
void ctr_internal_gui_cut(lv_obj_t* obj) {
379+
int issel = lv_textarea_text_is_selected(obj);
380+
if (!issel) return;
381+
lv_obj_t* txt = lv_textarea_get_label(obj);
382+
uint32_t selstart = lv_label_get_text_selection_start(txt);
383+
uint32_t selend = lv_label_get_text_selection_end(txt);
384+
char* oldbuf = lv_textarea_get_text(obj);
385+
uint32_t sellen = abs(selend - selstart);
386+
char* selbuf;
387+
selbuf = ctr_internal_gui_copytext(oldbuf, selstart, sellen);
388+
lv_label_cut_text(txt, selstart, sellen);
389+
SDL_SetClipboardText(selbuf);
390+
lv_textarea_set_cursor_pos(obj, selstart);
391+
ctr_heap_free(selbuf);
392+
lv_textarea_clear_selection(obj);
393+
}
394+
343395
void ctr_internal_gui_context_menu_close() {
344396
if (CtrGUIContextMenu) {
345397
lv_obj_del(CtrGUIContextMenu);
@@ -352,41 +404,18 @@ void ctr_internal_gui_context_actions(lv_event_t * e) {
352404
ctr_internal_gui_context_menu_close();
353405
return;
354406
}
355-
int issel = lv_textarea_text_is_selected(CtrGUIContextFocus);
356407
lv_obj_t * obj = lv_event_get_target_obj(e);
357-
lv_obj_t* txt = lv_textarea_get_label(CtrGUIContextFocus);
358-
uint32_t selstart = lv_label_get_text_selection_start(txt);
359-
uint32_t selend = lv_label_get_text_selection_end(txt);
360-
char* oldbuf = lv_textarea_get_text(CtrGUIContextFocus);
361-
uint32_t sellen = selend - selstart;
362-
char* selbuf;
363408
int close = 1;
364-
uint32_t pos = lv_textarea_get_cursor_pos(CtrGUIContextFocus);
365409
if ((obj == CtrGUIContextMenuItemSelAll || obj == CtrGUIContextMenuLabelSelAll)) {
366410
lv_textarea_selection_all(CtrGUIContextFocus);
367411
close = 0;
368-
} else if (issel && (obj == CtrGUIContextMenuItemCopy || obj == CtrGUIContextMenuLabelCopy)) {
369-
selbuf = ctr_internal_gui_copytext(oldbuf, selstart, sellen);
370-
SDL_SetClipboardText(selbuf);
371-
ctr_heap_free(selbuf);
372-
} else if (issel && (obj == CtrGUIContextMenuItemCut || obj == CtrGUIContextMenuLabelCut)) {
373-
selbuf = ctr_internal_gui_copytext(oldbuf, selstart, sellen);
374-
lv_label_cut_text(txt, selstart, sellen);
375-
SDL_SetClipboardText(selbuf);
376-
lv_textarea_set_cursor_pos(CtrGUIContextFocus, selstart);
377-
ctr_heap_free(selbuf);
412+
} else if ((obj == CtrGUIContextMenuItemCopy || obj == CtrGUIContextMenuLabelCopy)) {
413+
ctr_internal_gui_copy(CtrGUIContextFocus);
414+
} else if ((obj == CtrGUIContextMenuItemCut || obj == CtrGUIContextMenuLabelCut)) {
415+
ctr_internal_gui_cut(CtrGUIContextFocus);
378416
}
379417
else if (obj == CtrGUIContextMenuItemPaste || obj == CtrGUIContextMenuLabelPaste) {
380-
if (SDL_HasClipboardText()) {
381-
if (issel) lv_label_cut_text(txt, selstart, sellen);
382-
selbuf = SDL_GetClipboardText();
383-
lv_label_ins_text(txt, pos, selbuf);
384-
if (issel) {
385-
lv_textarea_set_cursor_pos(CtrGUIContextFocus, pos+sellen);
386-
lv_textarea_clear_selection(CtrGUIContextFocus);
387-
}
388-
SDL_free(selbuf);
389-
}
418+
ctr_internal_gui_paste(CtrGUIContextFocus);
390419
}
391420
if (close) ctr_internal_gui_context_menu_close();
392421
}
@@ -498,6 +527,9 @@ ctr_object* ctr_gui_xml_at_set(ctr_object* myself, ctr_argument* argumentList) {
498527
lv_obj_t* child = root;
499528
if (CtrEventHandler == NULL) {
500529
CtrEventHandler = lv_obj_add_event_cb(root, &ctr_gui_internal_event_handler, LV_EVENT_ALL, NULL);
530+
lv_textarea_set_copy_handler((LV_TEXTAREA_HANDLER) ctr_internal_gui_copy);
531+
lv_textarea_set_paste_handler((LV_TEXTAREA_HANDLER) ctr_internal_gui_paste);
532+
lv_textarea_set_cut_handler((LV_TEXTAREA_HANDLER) ctr_internal_gui_cut);
501533
}
502534
if (argumentList->next->next->object != CtrStdNil) {
503535
id = ctr_tonum(argumentList->next->next->object);

plugins/gui/lvgl_static/src/drivers/sdl/lv_sdl_keyboard.c

+6
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,12 @@ static uint32_t keycode_to_ctrl_key(SDL_Keycode sdl_key)
195195
switch(sdl_key) {
196196
case SDLK_a:
197197
return LV_KEY_SELECT_ALL;
198+
case SDLK_c:
199+
return LV_KEY_COPY;
200+
case SDLK_v:
201+
return LV_KEY_PASTE;
202+
case SDLK_x:
203+
return LV_KEY_CUT;
198204
}
199205
}
200206

plugins/gui/lvgl_static/src/widgets/textarea/lv_textarea.c

+51
Original file line numberDiff line numberDiff line change
@@ -843,6 +843,51 @@ void lv_textarea_clear_selection(lv_obj_t * obj)
843843
#endif
844844
}
845845

846+
LV_TEXTAREA_HANDLER lv_textarea_copy_handler = NULL;
847+
LV_TEXTAREA_HANDLER lv_textarea_paste_handler = NULL;
848+
LV_TEXTAREA_HANDLER lv_textarea_cut_handler = NULL;
849+
850+
void lv_textarea_set_copy_handler(LV_TEXTAREA_HANDLER handler) {
851+
lv_textarea_copy_handler = handler;
852+
}
853+
854+
void lv_textarea_set_paste_handler(LV_TEXTAREA_HANDLER handler) {
855+
lv_textarea_paste_handler = handler;
856+
}
857+
858+
void lv_textarea_set_cut_handler(LV_TEXTAREA_HANDLER handler) {
859+
lv_textarea_cut_handler = handler;
860+
}
861+
862+
void lv_textarea_copy(lv_obj_t * obj) {
863+
LV_ASSERT_OBJ(obj, MY_CLASS);
864+
#if LV_LABEL_TEXT_SELECTION
865+
if (lv_textarea_copy_handler) lv_textarea_copy_handler(obj);
866+
#else
867+
LV_UNUSED(obj); /*Unused*/
868+
#endif
869+
}
870+
871+
void lv_textarea_paste(lv_obj_t * obj) {
872+
LV_ASSERT_OBJ(obj, MY_CLASS);
873+
#if LV_LABEL_TEXT_SELECTION
874+
if (lv_textarea_paste_handler) lv_textarea_paste_handler(obj);
875+
#else
876+
LV_UNUSED(obj); /*Unused*/
877+
#endif
878+
}
879+
880+
void lv_textarea_cut(lv_obj_t * obj) {
881+
LV_ASSERT_OBJ(obj, MY_CLASS);
882+
#if LV_LABEL_TEXT_SELECTION
883+
if (lv_textarea_cut_handler) {
884+
lv_textarea_cut_handler(obj);
885+
}
886+
#else
887+
LV_UNUSED(obj); /*Unused*/
888+
#endif
889+
}
890+
846891
void lv_textarea_selection_all(lv_obj_t * obj) {
847892
LV_ASSERT_OBJ(obj, MY_CLASS);
848893
#if LV_LABEL_TEXT_SELECTION
@@ -1058,6 +1103,12 @@ static void lv_textarea_event(const lv_obj_class_t * class_p, lv_event_t * e)
10581103
uint32_t c = *((uint32_t *)lv_event_get_param(e)); /*uint32_t because can be UTF-8*/
10591104
if (c == LV_KEY_SELECT_ALL)
10601105
lv_textarea_selection_all(obj);
1106+
else if (c == LV_KEY_COPY)
1107+
lv_textarea_copy(obj);
1108+
else if (c == LV_KEY_PASTE)
1109+
lv_textarea_paste(obj);
1110+
else if (c == LV_KEY_CUT)
1111+
lv_textarea_cut(obj);
10611112
else if (c == LV_KEY_SELECT_RIGHT) {
10621113
lv_textarea_selection_start(obj);
10631114
lv_textarea_cursor_right(obj);

plugins/gui/lvgl_static/src/widgets/textarea/lv_textarea.h

+7
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ extern "C" {
2929

3030
LV_EXPORT_CONST_INT(LV_TEXTAREA_CURSOR_LAST);
3131

32+
3233
/**********************
3334
* TYPEDEFS
3435
**********************/
@@ -60,6 +61,8 @@ enum {
6061
LV_PART_TEXTAREA_PLACEHOLDER = LV_PART_CUSTOM_FIRST,
6162
};
6263

64+
typedef void (*LV_TEXTAREA_HANDLER)(lv_obj_t* t);
65+
6366
/**********************
6467
* GLOBAL PROTOTYPES
6568
**********************/
@@ -204,6 +207,10 @@ void lv_textarea_set_password_show_time(lv_obj_t * obj, uint32_t time);
204207
*/
205208
void lv_textarea_set_align(lv_obj_t * obj, lv_text_align_t align);
206209

210+
void lv_textarea_set_copy_handler(LV_TEXTAREA_HANDLER handler);
211+
void lv_textarea_set_paste_handler(LV_TEXTAREA_HANDLER handler);
212+
void lv_textarea_set_cut_handler(LV_TEXTAREA_HANDLER handler);
213+
207214
/*=====================
208215
* Getter functions
209216
*====================*/

0 commit comments

Comments
 (0)