~ubuntu-branches/ubuntu/trusty/fldigi/trusty

« back to all changes in this revision

Viewing changes to src/widgets/TextView.cxx

  • Committer: Bazaar Package Importer
  • Author(s): Joop Stakenborg
  • Date: 2008-11-17 19:40:43 UTC
  • mfrom: (1.1.6 upstream) (2.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20081117194043-sfe108e41ppsyhxr
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// ----------------------------------------------------------------------------
2
 
//
3
 
//      TextView.cxx
4
 
//
5
 
// Copyright (C) 2006
6
 
//              Dave Freese, W1HKJ
7
 
//
8
 
// This file is part of fldigi.
9
 
//
10
 
// fldigi is free software; you can redistribute it and/or modify
11
 
// it under the terms of the GNU General Public License as published by
12
 
// the Free Software Foundation; either version 2 of the License, or
13
 
// (at your option) any later version.
14
 
//
15
 
// fldigi is distributed in the hope that it will be useful,
16
 
// but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 
// GNU General Public License for more details.
19
 
//
20
 
// You should have received a copy of the GNU General Public License
21
 
// along with fldigi; if not, write to the Free Software
22
 
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23
 
// ----------------------------------------------------------------------------
24
 
 
25
 
#include <config.h>
26
 
 
27
 
#include <iostream>
28
 
#include <fstream>
29
 
#include <stdio.h>
30
 
#include <stdlib.h>
31
 
 
32
 
#include "TextView.h"
33
 
#include "main.h"
34
 
 
35
 
#include "macros.h"
36
 
#include "main.h"
37
 
 
38
 
#include "cw.h"
39
 
#include "misc.h"
40
 
 
41
 
#include <FL/Enumerations.H>
42
 
#include "File_Selector.h"
43
 
 
44
 
#include "ascii.h"
45
 
#include "qrunner.h"
46
 
 
47
 
using namespace std;
48
 
 
49
 
//=====================================================================
50
 
// class textview
51
 
// a virtual base class for building either a text viewer or editor
52
 
// you cannot instantiate this class by itself
53
 
// only as a base for child classes
54
 
//
55
 
// text is stored in <string> arrays
56
 
// the attribute of each character is mirrored in another <string> array
57
 
//=====================================================================
58
 
 
59
 
#define SBwidth 16
60
 
 
61
 
textview :: textview( int x, int y, int w, int h, const char *label )
62
 
  : ReceiveWidget( x, y, w, h, label ),
63
 
    adjusted_colours(false), scrollbar(x+w-SBwidth, y+2, SBwidth, h-4 )
64
 
{
65
 
        scrollbar.linesize( 1 );
66
 
        scrollbar.callback( _scrollbarCB, this );
67
 
 
68
 
        box( FL_DOWN_BOX );
69
 
        color( FL_BACKGROUND2_COLOR );
70
 
 
71
 
        TextFont = FL_SCREEN;
72
 
        TextSize = FL_NORMAL_SIZE;
73
 
        
74
 
        for (unsigned i = 0; i < sizeof(TextColor)/sizeof(TextColor[0]); i++) {
75
 
                TextColor[i] = FL_FOREGROUND_COLOR;
76
 
        }
77
 
        TextColor[ReceiveWidget::RECV] = FL_FOREGROUND_COLOR;
78
 
        TextColor[ReceiveWidget::XMIT] = FL_RED;
79
 
        TextColor[ReceiveWidget::CTRL] = FL_DARK_GREEN;
80
 
        TextColor[ReceiveWidget::SKIP] = FL_BLUE;
81
 
        TextColor[ReceiveWidget::ALTR] = FL_DARK_MAGENTA;
82
 
        
83
 
        wrappos = 0;
84
 
        cursorON = false;
85
 
        cursorwidth = 4;
86
 
        startidx = string::npos;
87
 
        laststartidx = string::npos;
88
 
    highlightstart = string::npos;
89
 
    highlightend = string::npos;
90
 
                
91
 
        H = h - 4;
92
 
        W = w - 4 - SBwidth;
93
 
        X = x + 2;
94
 
        Y = y + 2;
95
 
 
96
 
        clear();
97
 
}
98
 
 
99
 
textview :: ~textview()
100
 
{
101
 
}
102
 
 
103
 
void textview::Show() {
104
 
        scrollbar.show();
105
 
        show();
106
 
}
107
 
 
108
 
void textview::Hide() {
109
 
        scrollbar.hide();
110
 
        hide();
111
 
}
112
 
 
113
 
int textview::handle(int event)
114
 
{
115
 
        if (!adjusted_colours && event == FL_SHOW) {
116
 
                adjust_colours();
117
 
                adjusted_colours = true;
118
 
        }
119
 
 
120
 
        return 0;
121
 
}
122
 
 
123
 
void textview::setFont(Fl_Font fnt)
124
 
{
125
 
        FL_LOCK_D();
126
 
        TextFont = fnt;
127
 
        damage(FL_DAMAGE_ALL);
128
 
        FL_UNLOCK_D();
129
 
        FL_AWAKE_D();
130
 
}
131
 
 
132
 
void textview::setFontSize(int siz)
133
 
{
134
 
        FL_LOCK_D();
135
 
        TextSize = siz;
136
 
        damage(FL_DAMAGE_ALL);
137
 
        FL_UNLOCK_D();
138
 
        FL_AWAKE_D();
139
 
}
140
 
 
141
 
void textview::setFontColor(Fl_Color clr)
142
 
{
143
 
}
144
 
 
145
 
int textview::lineCount()
146
 
{
147
 
        int cnt = 1;
148
 
        size_t len = buff.length();
149
 
        if (len == 0)
150
 
                cnt = 0;
151
 
        else
152
 
                for (size_t n = 0; n < len; n++)
153
 
                        if (buff[n] == '\n') cnt++;
154
 
        return cnt;
155
 
}
156
 
 
157
 
size_t textview::linePosition(int linenbr)
158
 
{
159
 
        size_t len = buff.length();
160
 
        size_t pos = 0;
161
 
        while (linenbr && (pos < len) ) {
162
 
                if (buff[pos] == '\n')
163
 
                        --linenbr;
164
 
                pos++;
165
 
        }
166
 
        if (pos == len) return 0;
167
 
        return pos;
168
 
}
169
 
 
170
 
size_t textview::xy2bufidx()
171
 
{
172
 
    size_t idx = startidx;
173
 
        size_t len = buff.length();
174
 
        int xc = 0, yc = 0;
175
 
    int cheight, cwidth, descent;
176
 
        char c; 
177
 
 
178
 
    if (!len) return string::npos;
179
 
 
180
 
        fl_font(TextFont, TextSize);
181
 
    cheight = (int)fl_height();
182
 
    descent = fl_descent();
183
 
 
184
 
        while(idx < len) {
185
 
                if (yc > H) 
186
 
                        break;
187
 
                while (idx < len ) {
188
 
                        c = buff[idx];
189
 
            cwidth = (int)fl_width(c);
190
 
                        if (c == '\n') {
191
 
                                xc = 0;
192
 
                                yc += cheight;
193
 
                                break;
194
 
                        }
195
 
            if ( (popx >= xc && (popx < (xc + cwidth))) &&
196
 
                 (popy >= yc && (popy < (yc + charheight + descent))) ) {
197
 
                                return idx;
198
 
                        }
199
 
            idx++;
200
 
            xc += cwidth;
201
 
                }
202
 
                idx++;
203
 
        }
204
 
    return string::npos;
205
 
}
206
 
 
207
 
void textview::highlight(bool b)
208
 
{
209
 
    if (highlightstart == string::npos || highlightend == string::npos)
210
 
        return;
211
 
    if (b)
212
 
        for (size_t n = highlightstart; n <= highlightend; n++)
213
 
            attr[n] |= 0x20;
214
 
    else
215
 
        for (size_t n = highlightstart; n <= highlightend; n++)
216
 
            attr[n] &= 0x0F;
217
 
    damage(FL_DAMAGE_ALL);        
218
 
}
219
 
 
220
 
void textview::adjust_colours(void)
221
 
{
222
 
        for (int i = 0; i < NATTR; i++) {
223
 
                Fl_Color adj;
224
 
 
225
 
                while ((adj = fl_contrast(TextColor[i],
226
 
                                          FL_BACKGROUND2_COLOR)) != TextColor[i]) {
227
 
                        TextColor[i] = (adj == FL_WHITE) ?
228
 
                                fl_lighter(TextColor[i]) :
229
 
                                fl_darker(TextColor[i]);
230
 
                }
231
 
        }
232
 
}
233
 
 
234
 
 
235
 
string textview::findtext()
236
 
{
237
 
        size_t idx, wordstart, wordend;
238
 
        selword = "";
239
 
 
240
 
    idx = xy2bufidx();
241
 
    if (idx != string::npos) {
242
 
                wordstart = buff.find_last_of(" \n", idx);
243
 
                if (wordstart == string::npos) 
244
 
            wordstart = 0;
245
 
        else
246
 
            wordstart++;
247
 
                wordend = buff.find_first_of(" ,\n", idx);
248
 
                if (wordend == string::npos) 
249
 
            wordend = buff.length();
250
 
                selword = buff.substr(wordstart, wordend - wordstart);
251
 
                return selword;
252
 
        }
253
 
        return selword;
254
 
}
255
 
 
256
 
 
257
 
void textview::highlightword()
258
 
{
259
 
        size_t idx, wordstart, wordend;
260
 
 
261
 
    idx = xy2bufidx();
262
 
    highlightstart = highlightend = string::npos;
263
 
    if (idx != string::npos) {
264
 
                wordstart = buff.find_last_of(" \n", idx);
265
 
                if (wordstart == string::npos) 
266
 
            wordstart = 0;
267
 
        else
268
 
            wordstart++;
269
 
                wordend = buff.find_first_of(" ,\n", idx);
270
 
                if (wordend == string::npos) 
271
 
            wordend = buff.length();
272
 
        else
273
 
            wordend--;
274
 
        highlightstart = wordstart;
275
 
        highlightend = wordend;
276
 
        highlight(true);
277
 
        }
278
 
}
279
 
 
280
 
 
281
 
void textview::draw_cursor()
282
 
{
283
 
        if (cursorStyle == NONE) return;
284
 
  
285
 
        typedef struct { int x1, y1, x2, y2; } Segment;
286
 
 
287
 
        Segment segs[ 8 ];
288
 
        int nSegs = 0;
289
 
        int left = cursorX + 1,
290
 
                right = left + cursorwidth,
291
 
                bot = cursorY + descent - 2,
292
 
                top = cursorY - charheight + descent + 2;
293
 
 
294
 
  /* For cursors other than the block, make them around 2/3 of a character
295
 
     width, rounded to an even number of pixels so that X will draw an
296
 
     odd number centered on the stem at x. */
297
 
 
298
 
        if (cursorON == false)
299
 
                return;
300
 
 
301
 
        fl_color(FL_BACKGROUND2_COLOR);
302
 
        fl_rectf ( X + cursorX, Y + cursorY - charheight + descent, maxcharwidth, charheight);
303
 
 
304
 
  /* Create segments and draw cursor */
305
 
  if ( cursorStyle == CARET_CURSOR ) {
306
 
    int midY = top - charheight / 5;
307
 
    segs[ 0 ].x1 = left;                segs[ 0 ].y1 = top;             segs[ 0 ].x2 = left;            segs[ 0 ].y2 = midY;
308
 
    segs[ 1 ].x1 = left;                segs[ 1 ].y1 = midY;    segs[ 1 ].x2 = right;           segs[ 1 ].y2 = top;
309
 
    segs[ 2 ].x1 = left;                segs[ 2 ].y1 = top;             segs[ 2 ].x2 = left;            segs[ 2 ].y2 = midY - 1;
310
 
    segs[ 3 ].x1 = left;                segs[ 3 ].y1 = midY - 1;segs[ 3 ].x2 = right;           segs[ 3 ].y2 = top;
311
 
    nSegs = 4;
312
 
  } else if ( cursorStyle == NORMAL_CURSOR ) {
313
 
        int midX = left + cursorwidth / 2;
314
 
    segs[ 0 ].x1 = left;                segs[ 0 ].y1 = bot;             segs[ 0 ].x2 = right;           segs[ 0 ].y2 = bot;
315
 
    segs[ 1 ].x1 = midX;                segs[ 1 ].y1 = bot;             segs[ 1 ].x2 = midX;            segs[ 1 ].y2 = top;
316
 
    segs[ 2 ].x1 = left;                segs[ 2 ].y1 = top;             segs[ 2 ].x2 = right;           segs[ 2 ].y2 = top;
317
 
    nSegs = 3;
318
 
  } else if ( cursorStyle == HEAVY_CURSOR ) {
319
 
        int topp1 = top + 1, botm1 = bot - 1,
320
 
                mid = left + cursorwidth / 2,
321
 
                midp1 = mid + 1;
322
 
    segs[ 0 ].x1 = mid;                 segs[ 0 ].y1 = bot;             segs[ 0 ].x2 = mid;                     segs[ 0 ].y2 = top;
323
 
    segs[ 1 ].x1 = midp1;               segs[ 1 ].y1 = bot;             segs[ 1 ].x2 = midp1;           segs[ 1 ].y2 = top;
324
 
    segs[ 3 ].x1 = left;                segs[ 3 ].y1 = bot;             segs[ 3 ].x2 = right;           segs[ 3 ].y2 = bot;
325
 
    segs[ 4 ].x1 = left;                segs[ 4 ].y1 = top;             segs[ 4 ].x2 = right;           segs[ 4 ].y2 = top;
326
 
    segs[ 5 ].x1 = left;                segs[ 5 ].y1 = botm1;   segs[ 5 ].x2 = right;           segs[ 5 ].y2 = botm1;
327
 
    segs[ 6 ].x1 = left;                segs[ 6 ].y1 = topp1;   segs[ 6 ].x2 = right;           segs[ 6 ].y2 = topp1;
328
 
    nSegs = 7;
329
 
  } else if ( cursorStyle == DIM_CURSOR ) {
330
 
        int midX = left + cursorwidth / 2;
331
 
    segs[ 0 ].x1 = left;                segs[ 0 ].y1 = bot;             segs[ 0 ].x2 = right;           segs[ 0 ].y2 = bot;
332
 
    segs[ 1 ].x1 = midX;                segs[ 1 ].y1 = bot;             segs[ 1 ].x2 = midX;            segs[ 1 ].y2 = top;
333
 
    segs[ 2 ].x1 = left;                segs[ 2 ].y1 = top;             segs[ 2 ].x2 = right;           segs[ 2 ].y2 = top;
334
 
    nSegs = 3;
335
 
  } else if ( cursorStyle == BLOCK_CURSOR ) {
336
 
    right = cursorX + maxcharwidth;
337
 
    segs[ 0 ].x1 = left;                segs[ 0 ].y1 = bot;             segs[ 0 ].x2 = right;           segs[ 0 ].y2 = bot;
338
 
    segs[ 1 ].x1 = right;               segs[ 1 ].y1 = bot;             segs[ 1 ].x2 = right;           segs[ 1 ].y2 = top;
339
 
    segs[ 2 ].x1 = right;               segs[ 2 ].y1 = top;             segs[ 2 ].x2 = left;            segs[ 2 ].y2 = top;
340
 
    segs[ 3 ].x1 = left;                segs[ 3 ].y1 = top;             segs[ 3 ].x2 = left;            segs[ 3 ].y2 = bot;
341
 
    nSegs = 4;
342
 
  }
343
 
  fl_color( TextColor[ReceiveWidget::RECV] );
344
 
 
345
 
  for ( int k = 0; k < nSegs; k++ ) {
346
 
    fl_line( X + segs[ k ].x1, Y + segs[ k ].y1, X + segs[ k ].x2, Y + segs[ k ].y2 );
347
 
  }
348
 
}
349
 
 
350
 
void textview::drawall()
351
 
{
352
 
        int line = 0;
353
 
        size_t len = 0;
354
 
        char c = 0;
355
 
 
356
 
        fl_font(TextFont, TextSize);
357
 
        charheight = fl_height();
358
 
        maxcharwidth = (int)fl_width('X');
359
 
        descent = fl_descent();
360
 
 
361
 
        draw_box();
362
 
// resize the scrollbar to be a constant width
363
 
        scrollbar.resize( x()+w()-SBwidth, y()+2, SBwidth, h()-4 );
364
 
        scrollbar.redraw();
365
 
 
366
 
        cursorX = 0;
367
 
        cursorY = charheight - descent;
368
 
        endidx = 0;
369
 
        if ((len = buff.length()) == 0) {
370
 
                fl_push_clip( X, Y, W, H);
371
 
                draw_cursor();
372
 
                fl_pop_clip();
373
 
        return;
374
 
        }
375
 
 
376
 
        nlines = lineCount();
377
 
        line = nlines - H / charheight - scrollbar.value();
378
 
          
379
 
        startidx = linePosition(line);
380
 
        endidx = startidx;
381
 
        
382
 
        fl_push_clip( X, Y, W, H );
383
 
 
384
 
        memset(cstr, 0, 1000);
385
 
        int pos = 0;
386
 
        int a;
387
 
  
388
 
        while(endidx < len) {
389
 
                if (cursorY > H) 
390
 
                        break;
391
 
                while (endidx < len ) {
392
 
                        c = buff[endidx];
393
 
                        a = attr[endidx];
394
 
                        if (c == '\n') {
395
 
                                cursorX = 0;
396
 
                                cursorY += charheight;
397
 
                                endidx++;
398
 
                                memset(cstr, 0, 1000);
399
 
                                pos = 0;
400
 
                                break;
401
 
                        }
402
 
                        cstr[pos++] = c;
403
 
            if ((a & 0x20) == 0x20) {
404
 
                fl_color(FL_SELECTION_COLOR);
405
 
                    fl_rectf ( X + cursorX, Y + cursorY - charheight + descent, maxcharwidth, charheight);
406
 
                                fl_color (TextColor[(int)a & 0x0F]);
407
 
                                fl_draw ( cstr, 1, X + cursorX, Y + cursorY );
408
 
                                cursorX += (int)fl_width(c);
409
 
                                pos = 0;
410
 
                                endidx++;
411
 
            } else {
412
 
                endidx++;
413
 
                c = buff[endidx];
414
 
                                while (endidx < len && c != '\n' && a == attr[endidx] && pos < 999) {
415
 
                                        cstr[pos++] = c;
416
 
                                        ++endidx;
417
 
                                        c = buff[endidx];
418
 
                                } 
419
 
                                fl_color (TextColor[(int)a & 0x0F]);
420
 
                                fl_draw ( cstr, X + cursorX, Y + cursorY );
421
 
                                cursorX += (int)fl_width(cstr);
422
 
                                memset(cstr, 0, 1000);
423
 
                                pos = 0;
424
 
            }
425
 
                }
426
 
        }
427
 
        laststartidx = startidx;
428
 
        
429
 
        draw_cursor();
430
 
        fl_pop_clip();
431
 
}
432
 
 
433
 
void textview::drawchars()
434
 
{
435
 
        int line = 0;
436
 
        size_t startidx = string::npos;
437
 
        size_t len = 0;
438
 
        char c = 0;
439
 
        int a = 0;
440
 
        char cstr[] = " ";
441
 
  
442
 
        if ((len = buff.length()) == 0) {
443
 
                drawall();
444
 
                return;
445
 
        }
446
 
 
447
 
        fl_font(TextFont, TextSize);
448
 
        charheight = fl_height();
449
 
        descent = fl_descent();
450
 
        maxcharwidth = (int)fl_width('X');
451
 
 
452
 
        nlines = lineCount();
453
 
        line = nlines - H / charheight - scrollbar.value();
454
 
          
455
 
        startidx = linePosition(line);
456
 
        if (startidx != laststartidx) {
457
 
                drawall();
458
 
                return;
459
 
        }
460
 
 
461
 
        fl_push_clip( X, Y, W, H );
462
 
 
463
 
        while (endidx < len) {
464
 
                fl_color(FL_BACKGROUND2_COLOR);
465
 
                fl_rectf ( X + cursorX, Y + cursorY - charheight + descent, maxcharwidth, charheight);
466
 
                c = buff[endidx];
467
 
                a = attr[endidx];
468
 
                if (c == '\n') {
469
 
                        cursorX = 0;
470
 
                        cursorY += charheight;
471
 
                } else {
472
 
                        cstr[0] = c;
473
 
            if ((a & 0x20) == 0x20)
474
 
                fl_color(FL_SELECTION_COLOR);
475
 
            else
476
 
                                fl_color (TextColor[a & 0x0F]);
477
 
                        fl_draw ( cstr, 1, X + cursorX, Y + cursorY );
478
 
                        cursorX += (int)fl_width(c);
479
 
                }
480
 
                endidx++;
481
 
        }
482
 
        laststartidx = startidx;
483
 
        
484
 
        draw_cursor();
485
 
        fl_pop_clip();
486
 
}
487
 
 
488
 
void textview::drawmodify(size_t modidx)
489
 
{
490
 
    if (modidx < laststartidx )
491
 
        return;
492
 
    if (modidx > endidx)
493
 
        return;
494
 
    if (buff[modidx] == '\n')
495
 
        return;
496
 
// modify the character insitu
497
 
// find the screen location for the character redraw
498
 
    size_t posidx = laststartidx;
499
 
    int posX = 0, posY = charheight - descent;
500
 
    char c = 0;
501
 
    
502
 
        fl_font(TextFont, TextSize);
503
 
        while (posidx < modidx) {
504
 
                c = buff[posidx];
505
 
                if (c == '\n') {
506
 
                        posX = 0;
507
 
                        posY += charheight;
508
 
                } else {
509
 
                        posX += (int)(fl_width(c));
510
 
                }
511
 
                posidx++;
512
 
        }
513
 
// should now be pointing to the (x,y) screen location for the character
514
 
        char cstr[] = "";
515
 
    cstr[0] = buff[modidx];
516
 
// erase existing
517
 
    if ((attr[modidx] & 0x20) == 0x20)
518
 
        fl_color(FL_SELECTION_COLOR);
519
 
    else
520
 
        fl_color(FL_BACKGROUND2_COLOR);
521
 
        fl_rectf ( X + posX, Y + posY - charheight + descent, (int)fl_width(c), charheight);
522
 
// draw new with attribute
523
 
        fl_color (TextColor[(int)attr[modidx] & 0x0F]);
524
 
        fl_draw ( cstr, 1, X + posX, Y + posY );
525
 
}
526
 
 
527
 
void textview::draw()
528
 
{
529
 
        if (damage() & FL_DAMAGE_ALL) {
530
 
                drawall();
531
 
                return;
532
 
        }
533
 
        if (damage() & (FL_DAMAGE_ALL | 1)) {
534
 
                drawchars();
535
 
                return;
536
 
        }
537
 
        if (damage() & (FL_DAMAGE_ALL | 2)) {
538
 
                draw_cursor();
539
 
                return;
540
 
        }
541
 
        if (damage() & (FL_DAMAGE_ALL | 4)) {
542
 
                for (size_t i = draw_mod_range.start; i <= draw_mod_range.end; ++i)
543
 
                        drawmodify(i);
544
 
                draw_mod_range.start = draw_mod_range.end + 1;
545
 
                return;
546
 
        }
547
 
}
548
 
 
549
 
void textview::scrollbarCB()
550
 
{
551
 
        damage(FL_DAMAGE_ALL);
552
 
}
553
 
 
554
 
void textview::_backspace()
555
 
{
556
 
        int c;
557
 
        if (buff.empty()) return;
558
 
        
559
 
        size_t lastcrlf = buff.rfind('\n');
560
 
 
561
 
        if (lastcrlf == string::npos) lastcrlf = 0;
562
 
 
563
 
FL_LOCK_D();    
564
 
        if (attr[attr.length() - 1] == -1) { // soft linefeed skip over
565
 
                buff.erase(buff.length()-1);
566
 
                attr.erase(attr.length()-1);
567
 
                wrappos = 0;
568
 
                lastcrlf = buff.rfind('\n');
569
 
                if (lastcrlf == string::npos) lastcrlf = 0;
570
 
                fl_font(TextFont, TextSize);
571
 
                for (size_t i = lastcrlf; i < buff.length(); i++) {
572
 
                        wrappos += (int)(fl_width(buff[i]));
573
 
                }
574
 
        }
575
 
 
576
 
        c = buff[buff.length()-1];
577
 
        if (c == '\n') {
578
 
                buff.erase(buff.length()-1);
579
 
                attr.erase(attr.length()-1);
580
 
                wrappos = 0;
581
 
                lastcrlf = buff.rfind('\n');
582
 
                if (lastcrlf == string::npos) lastcrlf = 0;
583
 
                fl_font(TextFont, TextSize);
584
 
                for (size_t i = lastcrlf; i < buff.length(); i++) {
585
 
                        wrappos += (int)(fl_width(buff[i]));
586
 
                }
587
 
        } else {
588
 
                buff.erase(buff.length()-1);
589
 
                attr.erase(attr.length()-1);
590
 
                fl_font(TextFont, TextSize);
591
 
                wrappos -= (int)fl_width(c);
592
 
        }
593
 
        damage(FL_DAMAGE_ALL);
594
 
FL_UNLOCK_D();
595
 
FL_AWAKE_D();
596
 
}
597
 
 
598
 
void textview::add_( unsigned char c, int attribute)
599
 
{
600
 
        if (c == 0x08) {
601
 
                _backspace();
602
 
                return;
603
 
        }
604
 
 
605
 
        FL_LOCK_D();
606
 
        if (c >= ' ' && c <= '~') {
607
 
                buff += c;
608
 
                attr += attribute;
609
 
                fl_font(TextFont, TextSize);
610
 
                charwidth = (int)fl_width(c);
611
 
                if (charwidth > maxcharwidth)
612
 
                        maxcharwidth = charwidth;
613
 
                wrappos += charwidth;
614
 
        } else if (c == '\n') {
615
 
                buff += c;
616
 
                attr += attribute;
617
 
                wrappos = 0;
618
 
        }
619
 
 
620
 
        if (wrappos >= (w() - 24 - maxcharwidth)) {
621
 
                size_t lastspace = buff.find_last_of(' ');
622
 
                if (!wordwrap 
623
 
                        || lastspace == string::npos 
624
 
                        || (buff.length() - lastspace) >= 10
625
 
                        || (buff.length() - lastspace) == 1) {
626
 
                        buff += '\n';
627
 
                        attr += -1; // soft linefeed attribute
628
 
                        wrappos = 0;
629
 
                        damage(1);
630
 
                } else {
631
 
                        buff.insert(lastspace+1, 1, '\n');
632
 
                        attr.insert(lastspace+1, 1, -1);
633
 
                        wrappos = 0;
634
 
                        fl_font(TextFont, TextSize);
635
 
                        for (size_t i = lastspace+2; i < buff.length(); i++)
636
 
                                wrappos += (int)fl_width(buff[i]);
637
 
                        damage(FL_DAMAGE_ALL);
638
 
                }
639
 
        } else
640
 
                damage(1);
641
 
        FL_UNLOCK_D();
642
 
//      FL_AWAKE();
643
 
        
644
 
        setScrollbar();
645
 
}
646
 
 
647
 
void textview::add( unsigned char c, int attribute)
648
 
{
649
 
        if (c < ' ' || c == 127) { // we must look this up and insert it as a string
650
 
                unsigned char i = c;
651
 
                const char *cp = (attribute == CTRL) ? ascii2[i] : ascii[i];
652
 
                while (*cp)
653
 
                        add_(*cp++, attribute);
654
 
                return;
655
 
        }
656
 
 
657
 
        add_(c, attribute);
658
 
}
659
 
 
660
 
void textview::add( const char *text, int attr )
661
 
{
662
 
        while (*text)
663
 
                add_(*text++, attr);
664
 
}
665
 
 
666
 
void textview::clear()
667
 
{
668
 
        FL_LOCK_D();
669
 
        buff.erase();
670
 
        attr.erase();
671
 
    highlightstart = string::npos;
672
 
    highlightend = string::npos;
673
 
        wrappos = 0;
674
 
        startidx = string::npos;
675
 
        endidx = 0;
676
 
//      cursorX = 0;
677
 
//      cursorY = charheight;
678
 
        laststartidx = string::npos;
679
 
        setScrollbar();
680
 
        damage(FL_DAMAGE_ALL);
681
 
        FL_UNLOCK_D();
682
 
        FL_AWAKE_D();
683
 
}
684
 
 
685
 
 
686
 
void textview :: setScrollbar()
687
 
{
688
 
        int lines = lineCount();
689
 
        double size;
690
 
 
691
 
        fl_font(TextFont, TextSize);
692
 
        charheight = fl_height();
693
 
        scrollbar.range (lines, 0);
694
 
        if (lines * charheight <= h()-4)
695
 
                size = 1.0;
696
 
        else
697
 
                size = (double)(h()-4) / (double)(lines * charheight);
698
 
        if (size < 0.08) size = 0.08;
699
 
        scrollbar.slider_size( size );
700
 
}
701
 
 
702
 
void textview :: rebuildsoft(int W)
703
 
{
704
 
        size_t lfpos, chpos;
705
 
        if (W == w())
706
 
                return; // same width no rebuild needed
707
 
// remove all soft linefeeds
708
 
        while ((lfpos = attr.find(-1)) != string::npos) {
709
 
                buff.erase(lfpos, 1);
710
 
                attr.erase(lfpos, 1);
711
 
        }
712
 
        int endidx = W - 24 - maxcharwidth;
713
 
        wrappos = 0;
714
 
        chpos = 0;
715
 
        while (chpos < buff.length()) {
716
 
                if (buff[chpos] == '\n')
717
 
                        wrappos = 0;
718
 
                else
719
 
                        fl_font(TextFont, TextSize);
720
 
                        wrappos += (int)fl_width(buff[chpos]);
721
 
                if (wrappos >= endidx) {
722
 
                        size_t lastspace = buff.find_last_of(' ', chpos);
723
 
                        if (!wordwrap 
724
 
                                || lastspace == string::npos 
725
 
                                || (chpos - lastspace) >= 10
726
 
                                || (chpos == lastspace) ) {
727
 
                                buff.insert(chpos, 1, '\n');
728
 
                                attr.insert(chpos, 1, -1);
729
 
                                wrappos = 0;
730
 
                                chpos++;
731
 
                        } else {
732
 
                                buff.insert(lastspace+1, 1, '\n');
733
 
                                attr.insert(lastspace+1, 1, -1);
734
 
                                wrappos = 0;
735
 
                                chpos++;
736
 
                                fl_font(TextFont, TextSize);
737
 
                                for (size_t i = lastspace+2; i < chpos; i++)
738
 
                                        wrappos += (int)fl_width(buff[i]);
739
 
                        }
740
 
                }
741
 
                chpos++;
742
 
        }
743
 
}
744
 
 
745
 
void textview :: resize( int x, int y, int w, int h )
746
 
{
747
 
        rebuildsoft(w);
748
 
        H = h - 4;
749
 
        W = w - 4 - SBwidth;
750
 
        X = x + 2;
751
 
        Y = y + 2;
752
 
        Fl_Widget::resize( x, y, w, h );
753
 
        setScrollbar();
754
 
}
755
 
 
756
 
 
757
 
//=====================================================================
758
 
// Class TextView
759
 
// Viewer for received text
760
 
// derived from Class textview
761
 
//
762
 
// redefines the handle() and menu_cb() functions specified in the
763
 
// base class.  All other functions are in the base class
764
 
//=====================================================================
765
 
 
766
 
void TextView::saveFile()
767
 
{
768
 
        char * fn = File_Select(
769
 
                                        "Select ASCII text file", 
770
 
                                        "*.txt",
771
 
                                        "", 0);
772
 
        if (fn) {
773
 
                ofstream out(fn);
774
 
                out << buff;
775
 
                out.close();
776
 
        }
777
 
}
778
 
 
779
 
Fl_Menu_Item TextView::viewmenu[] = {
780
 
        {"@-9$returnarrow &QRZ this call",      0, 0 },                                 // 0
781
 
        {"@-9-> &Call",                         0, 0 },                                                 // 1
782
 
        {"@-9-> &Name",                         0, 0 },                                                 // 2
783
 
        {"@-9-> QT&H",                          0, 0 },                                                 // 3
784
 
        {"@-9-> &Locator",                      0, 0 },                                                 // 4
785
 
        {"@-9-> &RSTin",                        0, 0, 0, FL_MENU_DIVIDER },             // 5
786
 
        {"Insert divider",                      0, 0 },                                                 // 6
787
 
        {"C&lear",                              0, 0 },                                                         // 7
788
 
//      {"&Copy",                               0, 0, 0, FL_MENU_DIVIDER },
789
 
        {"Save to &file...",                    0, 0, 0, FL_MENU_DIVIDER },     // 8
790
 
        {"Word &wrap",                          0, 0, 0, FL_MENU_TOGGLE  },             // 9
791
 
        { 0 }
792
 
};
793
 
 
794
 
int viewmenuNbr = 10;
795
 
 
796
 
TextView::TextView( int x, int y, int w, int h, const char *label )
797
 
        : ReceiveWidget( x, y, w, h, label ), textview ( x, y, w, h, label )
798
 
{
799
 
        cursorStyle = NONE;// BLOCK_CURSOR;
800
 
        cursorON = true;
801
 
        wordwrap = true;
802
 
        viewmenu[9].set();
803
 
}
804
 
 
805
 
void TextView::menu_cb(int val)
806
 
{
807
 
//      handle(FL_UNFOCUS);
808
 
        switch (val) {
809
 
        case 0: // select call & do qrz query
810
 
                menu_cb(1);
811
 
                extern void QRZquery();
812
 
                QRZquery();
813
 
                break;
814
 
        case 1: // select call
815
 
                inpCall->value(findtext().c_str());
816
 
                break;
817
 
        case 2: // select name
818
 
                inpName->value(findtext().c_str());
819
 
                break;
820
 
        case 3: // select QTH
821
 
                inpQth->value(findtext().c_str());
822
 
                break;
823
 
        case 4: // select locator
824
 
                inpLoc->value(findtext().c_str());
825
 
                break;
826
 
        case 5: // select RST rcvd
827
 
                inpRstIn->value(findtext().c_str());
828
 
                break;
829
 
        case 6:
830
 
                add("\n     <<================>>\n", RECV);
831
 
                break;
832
 
        case 7:
833
 
                clear();
834
 
                break;
835
 
//      case 8: // clipboard copy
836
 
//              clipboard_copy();
837
 
//              break;
838
 
        case 8:
839
 
                saveFile();
840
 
                break;
841
 
 
842
 
        case 9: // wordwrap toggle
843
 
                wordwrap = !wordwrap;
844
 
                if (wordwrap)
845
 
                        viewmenu[9].set();
846
 
                else
847
 
                        viewmenu[9].clear();
848
 
                break;
849
 
        }
850
 
}
851
 
 
852
 
int TextView::handle(int event)
853
 
{
854
 
// handle events inside the textview and invoked by Right Mouse button or scrollbar
855
 
        if (Fl::event_inside( this )) {
856
 
                const Fl_Menu_Item * m;
857
 
                int xpos = Fl::event_x();
858
 
                int ypos = Fl::event_y();
859
 
                if (xpos > x() + w() - SBwidth) {
860
 
                        scrollbar.handle(event);
861
 
                        return 1;
862
 
                }
863
 
                if (event == FL_PUSH && Fl::event_button() == 3) {
864
 
                        popx = xpos - x();
865
 
                        popy = ypos - y();
866
 
            highlightword();
867
 
                        m = viewmenu->popup(xpos, ypos, 0, 0, 0);
868
 
                        if (m) {
869
 
                                for (int i = 0; i < viewmenuNbr; i++)
870
 
                                        if (m == &viewmenu[i]) {
871
 
                                                menu_cb(i);
872
 
                                                break;
873
 
                                        }
874
 
                        }
875
 
            highlight(false);
876
 
                        return 1;
877
 
                }
878
 
//        if (event == FL_PUSH && Fl::event_button() == 1) {
879
 
//            popx = xpos - x();
880
 
//            popy = ypos - y();
881
 
//            size_t pos = xy2bufidx();
882
 
//            if (pos != string::npos)
883
 
//                std::cout << buff[pos] << " @ " << pos << " ==> " << popx << ", " << popy << std::endl;
884
 
//            else
885
 
//                std::cout << "? position\n";
886
 
//            return 1;
887
 
//        }
888
 
 
889
 
        }
890
 
        return textview::handle(event);
891
 
}
892
 
 
893
 
//=====================================================================
894
 
// Class TextEdit
895
 
// derived from base class textview
896
 
// redfines the handle() and menu_cb() functions specified in the
897
 
// base class.  All other functions are in the base class
898
 
//=====================================================================
899
 
 
900
 
Fl_Menu_Item editmenu[] = {
901
 
        {"clear",       0, 0, 0, FL_MENU_DIVIDER },
902
 
        {"File",        0, 0, 0, FL_MENU_DIVIDER },
903
 
        {"^t",  0, 0 },
904
 
        {"^r",  0, 0, 0, FL_MENU_DIVIDER },
905
 
        {"Picture", 0, 0 },
906
 
        {0}
907
 
};
908
 
int editmenuNbr = 5;
909
 
 
910
 
TextEdit::TextEdit( int x, int y, int w, int h, const char *label )
911
 
        : ReceiveWidget( x, y, w, h, label ), textview ( x, y, w, h, label ),
912
 
          TransmitWidget( x, y, w, h, label )
913
 
{
914
 
        xmtidx = 0;
915
 
        bkspaces = 0;
916
 
        textview::cursorStyle = NORMAL_CURSOR;
917
 
        PauseBreak = false;
918
 
        wordwrap = false;
919
 
}
920
 
 
921
 
 
922
 
void TextEdit::readFile()
923
 
{
924
 
        char * fn = File_Select(
925
 
                                        "Select ASCII text file", 
926
 
                                        "*.txt",
927
 
                                        "", 0);
928
 
        if (fn)  {
929
 
                ifstream in(fn);
930
 
                if (in) {
931
 
                        char ch;
932
 
                        while (in.get(ch)) {
933
 
                                add_(ch, RECV);
934
 
                        }
935
 
                        in.close();
936
 
                }
937
 
        }
938
 
        Fl::focus(this);
939
 
}
940
 
 
941
 
void TextEdit::menu_cb(int val)
942
 
{
943
 
        if (val == 0) {
944
 
                clear();
945
 
                xmtidx = 0;
946
 
                bkspaces = 0;
947
 
        }
948
 
        if (val == 1)
949
 
                readFile();
950
 
        if (val == 2 && buff.empty()) {
951
 
                fl_lock(&trx_mutex);
952
 
                trx_state = STATE_TX;
953
 
                fl_unlock(&trx_mutex);
954
 
                wf->set_XmtRcvBtn(true);
955
 
        }
956
 
        if (val == 3)
957
 
                addstr("^r");
958
 
        if (val == 4)
959
 
                if (active_modem->get_mode() == MODE_MFSK16)
960
 
                        active_modem->makeTxViewer(0,0);
961
 
}
962
 
 
963
 
void TextEdit::clear() {
964
 
        textview::clear();
965
 
        xmtidx = 0;
966
 
        PauseBreak = false;
967
 
}
968
 
 
969
 
void TextEdit::clear_sent() {
970
 
        // FIXME: clear from 0 to xmtidx
971
 
        clear();
972
 
}
973
 
 
974
 
int TextEdit::handle_fnckey(int key) {
975
 
        int b = key - FL_F - 1;
976
 
        if (b > 11)
977
 
                return 0;
978
 
        
979
 
        b += altMacros * NUMMACKEYS;
980
 
        if (!(macros.text[b]).empty())
981
 
                macros.execute(b);
982
 
 
983
 
        return 1;
984
 
}
985
 
 
986
 
int TextEdit::handle_key() {
987
 
        int key = Fl::event_key();
988
 
        
989
 
        if (key == FL_Escape) {
990
 
                clear();
991
 
                active_modem->set_stopflag(true);
992
 
                Fl::focus(this);
993
 
                return 1;
994
 
        }
995
 
        
996
 
        if (key == FL_Pause) {
997
 
                if (trx_state != STATE_TX) {
998
 
                        fl_lock(&trx_mutex);
999
 
                        trx_state = STATE_TX;
1000
 
                        fl_unlock(&trx_mutex);
1001
 
                        wf->set_XmtRcvBtn(true);
1002
 
                } else
1003
 
                        PauseBreak = true;
1004
 
                Fl::focus(this);
1005
 
                return 1;
1006
 
        }
1007
 
        
1008
 
        if (key == (FL_KP + '+')) {
1009
 
                if (active_modem == cw_modem) active_modem->incWPM();
1010
 
                Fl::focus(this);
1011
 
                return 1;
1012
 
        }
1013
 
        if (key == (FL_KP + '-')) {
1014
 
                if (active_modem == cw_modem) active_modem->decWPM();
1015
 
                Fl::focus(this);
1016
 
                return 1;
1017
 
        }
1018
 
        if (key == (FL_KP + '*')) {
1019
 
                if (active_modem == cw_modem) active_modem->toggleWPM();
1020
 
                Fl::focus(this);
1021
 
                return 1;
1022
 
        }
1023
 
 
1024
 
        if (key >= FL_F && key <= FL_F_Last)
1025
 
                return handle_fnckey(key);
1026
 
                
1027
 
        if (key == FL_Tab && active_modem == cw_modem) {
1028
 
                while (xmtidx < buff.length()) {
1029
 
                        attr[xmtidx] = SKIP;
1030
 
                        xmtidx++;
1031
 
                }
1032
 
                damage(FL_DAMAGE_ALL);
1033
 
                Fl::focus(this);
1034
 
                return 1;
1035
 
        }
1036
 
 
1037
 
        if (key == FL_Left) {
1038
 
                active_modem->searchDown();
1039
 
                Fl::focus(this);
1040
 
                return 1;
1041
 
        }
1042
 
        if (key == FL_Right) {
1043
 
                active_modem->searchUp();
1044
 
                Fl::focus(this);
1045
 
                return 1;
1046
 
        }
1047
 
                
1048
 
        if (key == FL_Enter) {
1049
 
                add('\n');
1050
 
                Fl::focus(this);
1051
 
                return 1;
1052
 
        }
1053
 
        
1054
 
        if (key == FL_BackSpace) {
1055
 
                add (0x08);
1056
 
                if (xmtidx > buff.length()) {
1057
 
                        xmtidx = buff.length();
1058
 
                        bkspaces++;
1059
 
                }
1060
 
                Fl::focus(this);
1061
 
                return 1;
1062
 
        }
1063
 
        if (key == '1' || key == '2' || key == '3' || key == '4')
1064
 
                if (Fl::event_state() && FL_ALT) {
1065
 
                        altMacros = key - '1';
1066
 
                        for (int i = 0; i < 12; i++)
1067
 
                                btnMacro[i]->label(macros.name[i + (altMacros * NUMMACKEYS)].c_str());
1068
 
                        static char alt_text[4];
1069
 
                        snprintf(alt_text, sizeof(alt_text), "%d", altMacros + 1);
1070
 
                        btnAltMacros->label(alt_text);
1071
 
                        btnAltMacros->redraw_label();
1072
 
                        return 1;
1073
 
                }
1074
 
        
1075
 
        const char *ch = Fl::event_text();
1076
 
        addstr(ch);
1077
 
        Fl::focus(this);
1078
 
        return 1;
1079
 
}
1080
 
 
1081
 
int TextEdit::handle(int event)
1082
 
{
1083
 
// handle events inside the textedit widget
1084
 
        if (event == FL_UNFOCUS && Fl::focus() != this) {
1085
 
                textview::cursorON = false;
1086
 
                damage(3);
1087
 
                return 1;
1088
 
        }
1089
 
        if (event == FL_FOCUS) {
1090
 
                textview::cursorON = true;
1091
 
                damage(2);
1092
 
                return 1;
1093
 
        }
1094
 
        if (event == FL_KEYBOARD) {
1095
 
                return handle_key();
1096
 
        }
1097
 
        if (Fl::event_inside( this )) {
1098
 
                const Fl_Menu_Item * m;
1099
 
                int xpos = Fl::event_x();
1100
 
                int ypos = Fl::event_y();
1101
 
                if (xpos > x() + w() - SBwidth) {
1102
 
                        scrollbar.handle(event);
1103
 
                        Fl::focus(this);
1104
 
                        return 1;
1105
 
                }
1106
 
                if (event == FL_PUSH && Fl::event_button() == 3) {
1107
 
                        popx = xpos - x();
1108
 
                        popy = ypos - y();
1109
 
                        m = editmenu->popup(xpos, ypos, 0, 0, 0);
1110
 
                        if (m) {
1111
 
                                for (int i = 0; i < editmenuNbr; i++)
1112
 
                                        if (m == &editmenu[i]) {
1113
 
                                                menu_cb(i);
1114
 
                                                break;
1115
 
                                        }
1116
 
                        }
1117
 
                        Fl::focus(this);
1118
 
                        return 1;
1119
 
                }
1120
 
 
1121
 
                switch (event) {
1122
 
                        case FL_PUSH:
1123
 
                                textview::cursorON = true;
1124
 
                                damage(2);
1125
 
                                Fl::focus(this);
1126
 
                                return 1;
1127
 
                        case FL_FOCUS:
1128
 
                                textview::cursorON = true;
1129
 
                                damage(2);
1130
 
                                return 1;
1131
 
                        case FL_UNFOCUS:
1132
 
                                textview::cursorON = false;
1133
 
                                damage(2);
1134
 
                                return 1;
1135
 
                }
1136
 
        }
1137
 
        return textview::handle(event);
1138
 
}
1139
 
 
1140
 
int TextEdit::nextChar()
1141
 
{
1142
 
        if (bkspaces) {
1143
 
                --bkspaces;
1144
 
                return 0x08;
1145
 
        }
1146
 
        if (PauseBreak) {
1147
 
                PauseBreak = false;
1148
 
                return 0x03;
1149
 
        }
1150
 
        if (buff.empty()) return -1;
1151
 
        if (xmtidx == buff.length()) return -1;
1152
 
        if (attr[xmtidx] == -1) {
1153
 
                xmtidx++;
1154
 
                if (xmtidx == buff.length()) return -1;
1155
 
        }
1156
 
        FL_LOCK_D();
1157
 
        REQ(&TextEdit::update_xmit_text, this, xmtidx);
1158
 
        FL_UNLOCK_D();
1159
 
//    FL_AWAKE();
1160
 
        return (buff[xmtidx++]);
1161
 
}
1162
 
 
1163
 
void TextEdit::cursorON() 
1164
 
1165
 
        textview::cursorON = true; 
1166
 
        damage(2);
1167
 
}
1168
 
 
1169
 
void TextEdit::update_xmit_text(size_t i)
1170
 
{
1171
 
        attr[i] = XMIT;
1172
 
        if (draw_mod_range.start > i)
1173
 
                draw_mod_range.start = i;
1174
 
        draw_mod_range.end = i;
1175
 
        damage(4);
1176
 
}