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