1 /*===========================================================================
2 *
3 * PUBLIC DOMAIN NOTICE
4 * National Center for Biotechnology Information
5 *
6 * This software/database is a "United States Government Work" under the
7 * terms of the United States Copyright Act. It was written as part of
8 * the author's official duties as a United States Government employee and
9 * thus cannot be copyrighted. This software/database is freely available
10 * to the public for use. The National Library of Medicine and the U.S.
11 * Government have not placed any restriction on its use or reproduction.
12 *
13 * Although all reasonable efforts have been taken to ensure the accuracy
14 * and reliability of the software and data, the NLM and the U.S.
15 * Government do not and cannot warrant the performance or results that
16 * may be obtained by using this software or data. The NLM and the U.S.
17 * Government disclaim all warranties, express or implied, including
18 * warranties of performance, merchantability or fitness for any particular
19 * purpose.
20 *
21 * Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26
27 #include <klib/rc.h>
28 #include <klib/text.h>
29 #include <klib/printf.h>
30 #include <tui/tui_dlg.h>
31
32 #include "tui_widget.h"
33 #include "line_policy.h"
34
35 #define IL_CUR_POS 0 /* cursor-position */
36 #define IL_OFFSET 1 /* offset in case string is longer than visible windows */
37 #define IL_INS_MODE 2 /* 0...insert-mode, 1...overwrite-mode */
38 #define IL_ALPHA_MODE 3 /* 0...alpha/num-mode, 1...num-mode */
39
init_inputline(struct KTUIWidget * w)40 void init_inputline( struct KTUIWidget * w )
41 {
42 if ( w->txt != NULL )
43 {
44 w->ints[ IL_CUR_POS ] = string_measure ( w->txt, NULL ); /* cursor at the end of it... */
45 if ( w->ints[ IL_CUR_POS ] > ( w->r.w - 2 ) )
46 w->ints[ IL_OFFSET ] = ( w->ints[ IL_CUR_POS ] - ( w->r.w - 2 ) + 1 );
47 else
48 w->ints[ IL_OFFSET ] = 0;
49 }
50 w -> ints[ IL_INS_MODE ] = 0;
51 w -> ints[ IL_ALPHA_MODE ] = 0;
52 }
53
set_inputline_alpha_mode(struct KTUIWidget * w,uint32_t alpha_mode)54 void set_inputline_alpha_mode( struct KTUIWidget * w, uint32_t alpha_mode )
55 {
56 w->ints[ IL_ALPHA_MODE ] = alpha_mode;
57 }
58
draw_inputline_focused(struct KTUI * tui,tui_rect * r,const tui_ac * ac,const tui_ac * hint_ac,const char * s,uint32_t cursor_pos,uint32_t offset,uint32_t ins_mode)59 static rc_t draw_inputline_focused( struct KTUI * tui, tui_rect * r, const tui_ac * ac, const tui_ac * hint_ac,
60 const char * s, uint32_t cursor_pos, uint32_t offset, uint32_t ins_mode )
61 {
62 const char * txt = &( s[ offset ] );
63 uint32_t l = string_measure ( s, NULL );
64 /* draw the visible part of the string */
65 rc_t rc = DlgWrite( tui, r->top_left.x + 1, r->top_left.y, ac, txt, r->w - 2 );
66 if ( rc == 0 )
67 {
68 /* draw the cursor */
69 uint32_t x = r->top_left.x + 1 + cursor_pos - offset;
70 if ( x < ( r->top_left.x + ( r->w - 1 ) ) && x >= r->top_left.x )
71 {
72 if ( cursor_pos >= l )
73 rc = DlgWrite( tui, x, r->top_left.y, ac, "_", 1 );
74 else
75 {
76 char tmp[ 2 ];
77 tui_ac ac2;
78
79 tmp[ 0 ] = s[ cursor_pos ];
80 tmp[ 1 ] = 0;
81 copy_ac( &ac2, ac );
82 ac2.attr |= KTUI_a_underline;
83 if ( ins_mode != 0 )
84 ac2.attr |= KTUI_a_inverse;
85 rc = DlgWrite( tui, x, r->top_left.y, &ac2, tmp, 1 );
86 }
87 }
88 }
89
90 /* draw the hints that the content is longer than the visible part */
91 if ( rc == 0 && ( l > ( r->w - 2 ) ) )
92 {
93 if ( offset > 0 )
94 rc = DlgWrite( tui, r->top_left.x, r->top_left.y, hint_ac, "<", 1 );
95 if ( rc == 0 && ( l - offset ) > ( r->w - 2 ) )
96 rc = DlgWrite( tui, r->top_left.x + r->w - 1, r->top_left.y, hint_ac, ">", 1 );
97 }
98 return rc;
99 }
100
101
draw_inputline_normal(struct KTUI * tui,tui_rect * r,const tui_ac * ac,const char * s,uint32_t offset)102 static rc_t draw_inputline_normal( struct KTUI * tui, tui_rect * r, const tui_ac * ac,
103 const char * s, uint32_t offset )
104 {
105 const char * txt = &( s[ offset ] );
106 return DlgWrite( tui, r->top_left.x + 1, r->top_left.y, ac, txt, r->w - 2 );
107 }
108
109
draw_inputline(struct KTUIWidget * w)110 void draw_inputline( struct KTUIWidget * w )
111 {
112 tui_rect r;
113 rc_t rc = KTUIDlgAbsoluteRect ( w->dlg, &r, &w->r );
114 if ( rc == 0 )
115 {
116 tui_ac ac;
117 rc = GetWidgetAc( w, ktuipa_input, &ac );
118 if ( rc == 0 )
119 {
120 rc = draw_background( w->tui, w->focused, &r.top_left, r.w, r.h, ac.bg );
121 if ( rc == 0 && w->txt != NULL )
122 {
123 if ( w->focused )
124 {
125 const tui_ac * ac_hint = GetWidgetPaletteEntry ( w, ktuipa_input_hint );
126 rc = draw_inputline_focused( w->tui, &r, &ac, ac_hint, w->txt,
127 (uint32_t) w->ints[ IL_CUR_POS ],
128 (uint32_t) w->ints[ IL_OFFSET ],
129 (uint32_t) w->ints[ IL_INS_MODE ] );
130 }
131 else
132 rc = draw_inputline_normal( w->tui, &r, &ac, w->txt, (uint32_t) w->ints[ IL_OFFSET ] );
133 }
134 }
135 }
136 }
137
138
always_handle_these_keys(tui_event * event,uint32_t h)139 static bool always_handle_these_keys( tui_event * event, uint32_t h )
140 {
141 bool res = false;
142 if ( event->event_type == ktui_event_kb )
143 {
144 switch( event->data.kb_data.code )
145 {
146 case ktui_left :
147 case ktui_right : res = true; break;
148 case ktui_up :
149 case ktui_down : res = ( h > 1 ); break;
150 }
151 }
152 return res;
153 }
154
clip_cursor_pos(struct KTUIWidget * w)155 static void clip_cursor_pos( struct KTUIWidget * w )
156 {
157 uint32_t txt_len = string_measure ( w -> txt, NULL );
158 if ( w -> ints[ IL_CUR_POS ] > txt_len )
159 w -> ints[ IL_CUR_POS ] = txt_len;
160 }
161
event_inputline(struct KTUIWidget * w,tui_event * event,bool hotkey)162 bool event_inputline( struct KTUIWidget * w, tui_event * event, bool hotkey )
163 {
164 bool res;
165
166 lp_context lp;
167 lp . line = w -> txt;
168 lp . max_len = w -> txt_length;
169 lp . visible = ( w -> r . w - 2 );
170 lp . cur_pos = &( w -> ints[ IL_CUR_POS ] );
171 lp . offset = &( w -> ints[ IL_OFFSET ] );
172 lp . ins_mode = &( w -> ints[ IL_INS_MODE ] );
173 lp . alpha_mode = &( w -> ints[ IL_ALPHA_MODE ] );
174 lp . content_changed = false;
175 res = lp_handle_event( &lp, event );
176
177 if ( res )
178 {
179 if ( lp . content_changed )
180 SetWidgetChanged ( w, true );
181 RedrawWidgetAndPushEvent( w, ktuidlg_event_changed, w -> ints[ IL_CUR_POS ], 0, NULL );
182 }
183 else if ( event->event_type == ktui_event_kb && event->data.kb_data.code == ktui_enter )
184 {
185 KTUIDlgPushEvent( w->dlg, ktuidlg_event_select, w->id, 0, 0, NULL );
186 res = true;
187 }
188
189 if ( !res )
190 res = always_handle_these_keys( event, w->r.h );
191
192 return res;
193 }
194
set_carret_pos_input_line(struct KTUIWidget * w,size_t pos)195 void set_carret_pos_input_line( struct KTUIWidget * w, size_t pos )
196 {
197 w -> ints[ IL_CUR_POS ] = pos;
198 clip_cursor_pos( w );
199 draw_inputline( w );
200 }
201