Diffstat (limited to 'noncore/apps/opie-console/TEWidget.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | noncore/apps/opie-console/TEWidget.cpp | 1264 |
1 files changed, 1264 insertions, 0 deletions
diff --git a/noncore/apps/opie-console/TEWidget.cpp b/noncore/apps/opie-console/TEWidget.cpp new file mode 100644 index 0000000..75c438c --- a/dev/null +++ b/noncore/apps/opie-console/TEWidget.cpp | |||
@@ -0,0 +1,1264 @@ | |||
1 | /* ------------------------------------------------------------------------ */ | ||
2 | /* */ | ||
3 | /* [TEWidget.C] Terminal Emulation Widget */ | ||
4 | /* */ | ||
5 | /* ------------------------------------------------------------------------ */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* ------------------------------------------------------------------------ */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | /*! \class TEWidget | ||
19 | |||
20 | \brief Visible screen contents | ||
21 | |||
22 | This class is responsible to map the `image' of a terminal emulation to the | ||
23 | display. All the dependency of the emulation to a specific GUI or toolkit is | ||
24 | localized here. Further, this widget has no knowledge about being part of an | ||
25 | emulation, it simply work within the terminal emulation framework by exposing | ||
26 | size and key events and by being ordered to show a new image. | ||
27 | |||
28 | <ul> | ||
29 | <li> The internal image has the size of the widget (evtl. rounded up) | ||
30 | <li> The external image used in setImage can have any size. | ||
31 | <li> (internally) the external image is simply copied to the internal | ||
32 | when a setImage happens. During a resizeEvent no painting is done | ||
33 | a paintEvent is expected to follow anyway. | ||
34 | </ul> | ||
35 | |||
36 | \sa TEScreen \sa Emulation | ||
37 | */ | ||
38 | |||
39 | /* FIXME: | ||
40 | - 'image' may also be used uninitialized (it isn't in fact) in resizeEvent | ||
41 | - 'font_a' not used in mouse events | ||
42 | - add destructor | ||
43 | */ | ||
44 | |||
45 | /* TODO | ||
46 | - evtl. be sensitive to `paletteChange' while using default colors. | ||
47 | - set different 'rounding' styles? I.e. have a mode to show clipped chars? | ||
48 | */ | ||
49 | |||
50 | // #include "config.h" | ||
51 | #include "TEWidget.h" | ||
52 | #include "session.h" | ||
53 | #include <qpe/config.h> | ||
54 | |||
55 | #include <qapplication.h> | ||
56 | #include <qcursor.h> | ||
57 | #include <qregexp.h> | ||
58 | #include <qpainter.h> | ||
59 | #include <qclipboard.h> | ||
60 | #include <qstyle.h> | ||
61 | #include <qfile.h> | ||
62 | #include <qdragobject.h> | ||
63 | |||
64 | #include <stdio.h> | ||
65 | #include <stdlib.h> | ||
66 | #include <unistd.h> | ||
67 | #include <ctype.h> | ||
68 | #include <sys/stat.h> | ||
69 | #include <sys/types.h> | ||
70 | #include <signal.h> | ||
71 | |||
72 | #include <assert.h> | ||
73 | |||
74 | // #include "TEWidget.moc" | ||
75 | //#include <kapp.h> | ||
76 | //#include <kcursor.h> | ||
77 | //#include <kurl.h> | ||
78 | //#include <kdebug.h> | ||
79 | //#include <klocale.h> | ||
80 | |||
81 | #define HERE printf("%s(%d): %s\n",__FILE__,__LINE__,__FUNCTION__) | ||
82 | #define HCNT(Name) // { static int cnt = 1; printf("%s(%d): %s %d\n",__FILE__,__LINE__,Name,cnt++); } | ||
83 | |||
84 | #define loc(X,Y) ((Y)*columns+(X)) | ||
85 | |||
86 | //FIXME: the rim should normally be 1, 0 only when running in full screen mode. | ||
87 | #define rimX 0 // left/right rim width | ||
88 | #define rimY 0 // top/bottom rim high | ||
89 | |||
90 | #define SCRWIDTH 16 // width of the scrollbar | ||
91 | |||
92 | #define yMouseScroll 1 | ||
93 | // scroll increment used when dragging selection at top/bottom of window. | ||
94 | |||
95 | /* ------------------------------------------------------------------------- */ | ||
96 | /* */ | ||
97 | /* Colors */ | ||
98 | /* */ | ||
99 | /* ------------------------------------------------------------------------- */ | ||
100 | |||
101 | //FIXME: the default color table is in session.C now. | ||
102 | // We need a way to get rid of this one, here. | ||
103 | static const ColorEntry base_color_table[TABLE_COLORS] = | ||
104 | // The following are almost IBM standard color codes, with some slight | ||
105 | // gamma correction for the dim colors to compensate for bright X screens. | ||
106 | // It contains the 8 ansiterm/xterm colors in 2 intensities. | ||
107 | { | ||
108 | // Fixme: could add faint colors here, also. | ||
109 | // normal | ||
110 | ColorEntry(QColor(0x00,0x00,0x00), 0, 0 ), ColorEntry( QColor(0xB2,0xB2,0xB2), 1, 0 ), // Dfore, Dback | ||
111 | ColorEntry(QColor(0x00,0x00,0x00), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0x18), 0, 0 ), // Black, Red | ||
112 | ColorEntry(QColor(0x18,0xB2,0x18), 0, 0 ), ColorEntry( QColor(0xB2,0x68,0x18), 0, 0 ), // Green, Yellow | ||
113 | ColorEntry(QColor(0x18,0x18,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0xB2), 0, 0 ), // Blue, Magenta | ||
114 | ColorEntry(QColor(0x18,0xB2,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0xB2,0xB2), 0, 0 ), // Cyan, White | ||
115 | // intensiv | ||
116 | ColorEntry(QColor(0x00,0x00,0x00), 0, 1 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 1, 0 ), | ||
117 | ColorEntry(QColor(0x68,0x68,0x68), 0, 0 ), ColorEntry( QColor(0xFF,0x54,0x54), 0, 0 ), | ||
118 | ColorEntry(QColor(0x54,0xFF,0x54), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0x54), 0, 0 ), | ||
119 | ColorEntry(QColor(0x54,0x54,0xFF), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0xB2), 0, 0 ), | ||
120 | ColorEntry(QColor(0x54,0xFF,0xFF), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 0, 0 ) | ||
121 | }; | ||
122 | |||
123 | /* Note that we use ANSI color order (bgr), while IBMPC color order is (rgb) | ||
124 | |||
125 | Code 0 1 2 3 4 5 6 7 | ||
126 | ----------- ------- ------- ------- ------- ------- ------- ------- ------- | ||
127 | ANSI (bgr) Black Red Green Yellow Blue Magenta Cyan White | ||
128 | IBMPC (rgb) Black Blue Green Cyan Red Magenta Yellow White | ||
129 | */ | ||
130 | |||
131 | QColor TEWidget::getDefaultBackColor() | ||
132 | { | ||
133 | return color_table[DEFAULT_BACK_COLOR].color; | ||
134 | } | ||
135 | |||
136 | const ColorEntry* TEWidget::getColorTable() const | ||
137 | { | ||
138 | return color_table; | ||
139 | } | ||
140 | |||
141 | const ColorEntry* TEWidget::getdefaultColorTable() const | ||
142 | { | ||
143 | return base_color_table; | ||
144 | } | ||
145 | |||
146 | |||
147 | const QPixmap *TEWidget::backgroundPixmap() | ||
148 | { | ||
149 | static QPixmap *bg = new QPixmap("~/qpim/main/pics/faded_bg.xpm"); | ||
150 | const QPixmap *pm = bg; | ||
151 | return pm; | ||
152 | } | ||
153 | |||
154 | void TEWidget::setColorTable(const ColorEntry table[]) | ||
155 | { | ||
156 | for (int i = 0; i < TABLE_COLORS; i++) color_table[i] = table[i]; | ||
157 | |||
158 | const QPixmap* pm = backgroundPixmap(); | ||
159 | if (!pm) setBackgroundColor(color_table[DEFAULT_BACK_COLOR].color); | ||
160 | update(); | ||
161 | } | ||
162 | |||
163 | //FIXME: add backgroundPixmapChanged. | ||
164 | |||
165 | /* ------------------------------------------------------------------------- */ | ||
166 | /* */ | ||
167 | /* Font */ | ||
168 | /* */ | ||
169 | /* ------------------------------------------------------------------------- */ | ||
170 | |||
171 | /* | ||
172 | The VT100 has 32 special graphical characters. The usual vt100 extended | ||
173 | xterm fonts have these at 0x00..0x1f. | ||
174 | |||
175 | QT's iso mapping leaves 0x00..0x7f without any changes. But the graphicals | ||
176 | come in here as proper unicode characters. | ||
177 | |||
178 | We treat non-iso10646 fonts as VT100 extended and do the requiered mapping | ||
179 | from unicode to 0x00..0x1f. The remaining translation is then left to the | ||
180 | QCodec. | ||
181 | */ | ||
182 | |||
183 | // assert for i in [0..31] : vt100extended(vt100_graphics[i]) == i. | ||
184 | |||
185 | unsigned short vt100_graphics[32] = | ||
186 | { // 0/8 1/9 2/10 3/11 4/12 5/13 6/14 7/15 | ||
187 | 0x0020, 0x25C6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, | ||
188 | 0x00b1, 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, | ||
189 | 0xF800, 0xF801, 0x2500, 0xF803, 0xF804, 0x251c, 0x2524, 0x2534, | ||
190 | 0x252c, 0x2502, 0x2264, 0x2265, 0x03C0, 0x2260, 0x00A3, 0x00b7 | ||
191 | }; | ||
192 | |||
193 | static QChar vt100extended(QChar c) | ||
194 | { | ||
195 | switch (c.unicode()) | ||
196 | { | ||
197 | case 0x25c6 : return 1; | ||
198 | case 0x2592 : return 2; | ||
199 | case 0x2409 : return 3; | ||
200 | case 0x240c : return 4; | ||
201 | case 0x240d : return 5; | ||
202 | case 0x240a : return 6; | ||
203 | case 0x00b0 : return 7; | ||
204 | case 0x00b1 : return 8; | ||
205 | case 0x2424 : return 9; | ||
206 | case 0x240b : return 10; | ||
207 | case 0x2518 : return 11; | ||
208 | case 0x2510 : return 12; | ||
209 | case 0x250c : return 13; | ||
210 | case 0x2514 : return 14; | ||
211 | case 0x253c : return 15; | ||
212 | case 0xf800 : return 16; | ||
213 | case 0xf801 : return 17; | ||
214 | case 0x2500 : return 18; | ||
215 | case 0xf803 : return 19; | ||
216 | case 0xf804 : return 20; | ||
217 | case 0x251c : return 21; | ||
218 | case 0x2524 : return 22; | ||
219 | case 0x2534 : return 23; | ||
220 | case 0x252c : return 24; | ||
221 | case 0x2502 : return 25; | ||
222 | case 0x2264 : return 26; | ||
223 | case 0x2265 : return 27; | ||
224 | case 0x03c0 : return 28; | ||
225 | case 0x2260 : return 29; | ||
226 | case 0x00a3 : return 30; | ||
227 | case 0x00b7 : return 31; | ||
228 | } | ||
229 | return c; | ||
230 | } | ||
231 | |||
232 | static QChar identicalMap(QChar c) | ||
233 | { | ||
234 | return c; | ||
235 | } | ||
236 | |||
237 | void TEWidget::fontChange(const QFont &) | ||
238 | { | ||
239 | QFontMetrics fm(font()); | ||
240 | font_h = fm.height(); | ||
241 | font_w = fm.maxWidth(); | ||
242 | font_a = fm.ascent(); | ||
243 | //printf("font_h: %d\n",font_h); | ||
244 | //printf("font_w: %d\n",font_w); | ||
245 | //printf("font_a: %d\n",font_a); | ||
246 | //printf("charset: %s\n",QFont::encodingName(font().charSet()).ascii()); | ||
247 | //printf("rawname: %s\n",font().rawName().ascii()); | ||
248 | fontMap = | ||
249 | #if QT_VERSION < 300 | ||
250 | strcmp(QFont::encodingName(font().charSet()).ascii(),"iso10646") | ||
251 | ? vt100extended | ||
252 | : | ||
253 | #endif | ||
254 | identicalMap; | ||
255 | propagateSize(); | ||
256 | update(); | ||
257 | } | ||
258 | |||
259 | void TEWidget::setVTFont(const QFont& f) | ||
260 | { | ||
261 | QFrame::setFont(f); | ||
262 | } | ||
263 | |||
264 | QFont TEWidget::getVTFont() { | ||
265 | return font(); | ||
266 | } | ||
267 | |||
268 | void TEWidget::setFont(const QFont &) | ||
269 | { | ||
270 | // ignore font change request if not coming from konsole itself | ||
271 | } | ||
272 | |||
273 | /* ------------------------------------------------------------------------- */ | ||
274 | /* */ | ||
275 | /* Constructor / Destructor */ | ||
276 | /* */ | ||
277 | /* ------------------------------------------------------------------------- */ | ||
278 | |||
279 | TEWidget::TEWidget(QWidget *parent, const char *name) : QFrame(parent,name) | ||
280 | { | ||
281 | #ifndef QT_NO_CLIPBOARD | ||
282 | cb = QApplication::clipboard(); | ||
283 | QObject::connect( (QObject*)cb, SIGNAL(dataChanged()), | ||
284 | this, SLOT(onClearSelection()) ); | ||
285 | #endif | ||
286 | |||
287 | scrollbar = new QScrollBar(this); | ||
288 | scrollbar->setCursor( arrowCursor ); | ||
289 | connect(scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scrollChanged(int))); | ||
290 | |||
291 | Config cfg("Konsole"); | ||
292 | cfg.setGroup("ScrollBar"); | ||
293 | switch( cfg.readNumEntry("Position",2)){ | ||
294 | case 0: | ||
295 | scrollLoc = SCRNONE; | ||
296 | break; | ||
297 | case 1: | ||
298 | scrollLoc = SCRLEFT; | ||
299 | break; | ||
300 | case 2: | ||
301 | scrollLoc = SCRRIGHT; | ||
302 | break; | ||
303 | }; | ||
304 | |||
305 | blinkT = new QTimer(this); | ||
306 | connect(blinkT, SIGNAL(timeout()), this, SLOT(blinkEvent())); | ||
307 | // blinking = FALSE; | ||
308 | blinking = TRUE; | ||
309 | |||
310 | resizing = FALSE; | ||
311 | actSel = 0; | ||
312 | image = 0; | ||
313 | lines = 1; | ||
314 | columns = 1; | ||
315 | font_w = 1; | ||
316 | font_h = 1; | ||
317 | font_a = 1; | ||
318 | word_selection_mode = FALSE; | ||
319 | |||
320 | setMouseMarks(TRUE); | ||
321 | setVTFont( QFont("fixed") ); | ||
322 | setColorTable(base_color_table); // init color table | ||
323 | |||
324 | qApp->installEventFilter( this ); //FIXME: see below | ||
325 | // KCursor::setAutoHideCursor( this, true ); | ||
326 | |||
327 | // Init DnD //////////////////////////////////////////////////////////////// | ||
328 | currentSession = NULL; | ||
329 | // setAcceptDrops(true); // attempt | ||
330 | // m_drop = new QPopupMenu(this); | ||
331 | // m_drop->insertItem( QString("Paste"), 0); | ||
332 | // m_drop->insertItem( QString("cd"), 1); | ||
333 | // connect(m_drop, SIGNAL(activated(int)), SLOT(drop_menu_activated(int))); | ||
334 | |||
335 | // we need focus so that the auto-hide cursor feature works | ||
336 | setFocus(); | ||
337 | setFocusPolicy( WheelFocus ); | ||
338 | } | ||
339 | |||
340 | //FIXME: make proper destructor | ||
341 | // Here's a start (David) | ||
342 | TEWidget::~TEWidget() | ||
343 | { | ||
344 | qApp->removeEventFilter( this ); | ||
345 | if (image) free(image); | ||
346 | } | ||
347 | |||
348 | /* ------------------------------------------------------------------------- */ | ||
349 | /* */ | ||
350 | /* Display Operations */ | ||
351 | /* */ | ||
352 | /* ------------------------------------------------------------------------- */ | ||
353 | |||
354 | /*! | ||
355 | attributed string draw primitive | ||
356 | */ | ||
357 | |||
358 | void TEWidget::drawAttrStr(QPainter &paint, QRect rect, | ||
359 | QString& str, ca attr, BOOL pm, BOOL clear) | ||
360 | { | ||
361 | if (pm && color_table[attr.b].transparent) | ||
362 | { | ||
363 | paint.setBackgroundMode( TransparentMode ); | ||
364 | if (clear) erase(rect); | ||
365 | } | ||
366 | else | ||
367 | { | ||
368 | if (blinking) | ||
369 | paint.fillRect(rect, color_table[attr.b].color); | ||
370 | else | ||
371 | { | ||
372 | paint.setBackgroundMode( OpaqueMode ); | ||
373 | paint.setBackgroundColor( color_table[attr.b].color ); | ||
374 | } | ||
375 | } | ||
376 | |||
377 | if (color_table[attr.f].bold) | ||
378 | paint.setPen(QColor( 0x8F, 0x00, 0x00 )); | ||
379 | else | ||
380 | paint.setPen(color_table[attr.f].color); | ||
381 | |||
382 | paint.drawText(rect.x(),rect.y()+font_a, str); | ||
383 | |||
384 | if (attr.r & RE_UNDERLINE) | ||
385 | paint.drawLine(rect.left(), rect.y()+font_a+1, rect.right(),rect.y()+font_a+1 ); | ||
386 | } | ||
387 | |||
388 | /*! | ||
389 | The image can only be set completely. | ||
390 | |||
391 | The size of the new image may or may not match the size of the widget. | ||
392 | */ | ||
393 | |||
394 | void TEWidget::setImage(const ca* const newimg, int lines, int columns) | ||
395 | { int y,x,len; | ||
396 | const QPixmap* pm = backgroundPixmap(); | ||
397 | QPainter paint; | ||
398 | setUpdatesEnabled(FALSE); | ||
399 | paint.begin( this ); | ||
400 | HCNT("setImage"); | ||
401 | |||
402 | QPoint tL = contentsRect().topLeft(); | ||
403 | int tLx = tL.x(); | ||
404 | int tLy = tL.y(); | ||
405 | hasBlinker = FALSE; | ||
406 | |||
407 | int cf = -1; // undefined | ||
408 | int cb = -1; // undefined | ||
409 | int cr = -1; // undefined | ||
410 | |||
411 | int lins = QMIN(this->lines, QMAX(0,lines )); | ||
412 | int cols = QMIN(this->columns,QMAX(0,columns)); | ||
413 | QChar *disstrU = new QChar[cols]; | ||
414 | |||
415 | //{ static int cnt = 0; printf("setImage %d\n",cnt++); } | ||
416 | for (y = 0; y < lins; y++) | ||
417 | { | ||
418 | const ca* lcl = &image[y*this->columns]; | ||
419 | const ca* const ext = &newimg[y*columns]; | ||
420 | if (!resizing) // not while resizing, we're expecting a paintEvent | ||
421 | for (x = 0; x < cols; x++) | ||
422 | { | ||
423 | hasBlinker |= (ext[x].r & RE_BLINK); | ||
424 | if (ext[x] != lcl[x]) | ||
425 | { | ||
426 | cr = ext[x].r; | ||
427 | cb = ext[x].b; | ||
428 | if (ext[x].f != cf) cf = ext[x].f; | ||
429 | int lln = cols - x; | ||
430 | disstrU[0] = fontMap(ext[x+0].c); | ||
431 | for (len = 1; len < lln; len++) | ||
432 | { | ||
433 | if (ext[x+len].f != cf || ext[x+len].b != cb || ext[x+len].r != cr || | ||
434 | ext[x+len] == lcl[x+len] ) | ||
435 | break; | ||
436 | disstrU[len] = fontMap(ext[x+len].c); | ||
437 | } | ||
438 | QString unistr(disstrU,len); | ||
439 | drawAttrStr(paint, | ||
440 | QRect(blX+tLx+font_w*x,bY+tLy+font_h*y,font_w*len,font_h), | ||
441 | unistr, ext[x], pm != NULL, true); | ||
442 | x += len - 1; | ||
443 | } | ||
444 | } | ||
445 | // finally, make `image' become `newimg'. | ||
446 | memcpy((void*)lcl,(const void*)ext,cols*sizeof(ca)); | ||
447 | } | ||
448 | drawFrame( &paint ); | ||
449 | paint.end(); | ||
450 | setUpdatesEnabled(TRUE); | ||
451 | if ( hasBlinker && !blinkT->isActive()) blinkT->start(1000); // 1000 ms | ||
452 | if (!hasBlinker && blinkT->isActive()) { blinkT->stop(); blinking = FALSE; } | ||
453 | delete [] disstrU; | ||
454 | } | ||
455 | |||
456 | // paint Event //////////////////////////////////////////////////// | ||
457 | |||
458 | /*! | ||
459 | The difference of this routine vs. the `setImage' is, | ||
460 | that the drawing does not include a difference analysis | ||
461 | between the old and the new image. Instead, the internal | ||
462 | image is used and the painting bound by the PaintEvent box. | ||
463 | */ | ||
464 | |||
465 | void TEWidget::paintEvent( QPaintEvent* pe ) | ||
466 | { | ||
467 | |||
468 | //{ static int cnt = 0; printf("paint %d\n",cnt++); } | ||
469 | const QPixmap* pm = backgroundPixmap(); | ||
470 | QPainter paint; | ||
471 | setUpdatesEnabled(FALSE); | ||
472 | paint.begin( this ); | ||
473 | paint.setBackgroundMode( TransparentMode ); | ||
474 | HCNT("paintEvent"); | ||
475 | |||
476 | // Note that the actual widget size can be slightly larger | ||
477 | // that the image (the size is truncated towards the smaller | ||
478 | // number of characters in `resizeEvent'. The paint rectangle | ||
479 | // can thus be larger than the image, but less then the size | ||
480 | // of one character. | ||
481 | |||
482 | QRect rect = pe->rect().intersect(contentsRect()); | ||
483 | |||
484 | QPoint tL = contentsRect().topLeft(); | ||
485 | int tLx = tL.x(); | ||
486 | int tLy = tL.y(); | ||
487 | |||
488 | int lux = QMIN(columns-1, QMAX(0,(rect.left() - tLx - blX ) / font_w)); | ||
489 | int luy = QMIN(lines-1, QMAX(0,(rect.top() - tLy - bY ) / font_h)); | ||
490 | int rlx = QMIN(columns-1, QMAX(0,(rect.right() - tLx - blX ) / font_w)); | ||
491 | int rly = QMIN(lines-1, QMAX(0,(rect.bottom() - tLy - bY ) / font_h)); | ||
492 | |||
493 | /* | ||
494 | printf("paintEvent: %d..%d, %d..%d (%d..%d, %d..%d)\n",lux,rlx,luy,rly, | ||
495 | rect.left(), rect.right(), rect.top(), rect.bottom()); | ||
496 | */ | ||
497 | |||
498 | // if (pm != NULL && color_table[image->b].transparent) | ||
499 | // erase(rect); | ||
500 | // BL: I have no idea why we need this, and it breaks the refresh. | ||
501 | |||
502 | QChar *disstrU = new QChar[columns]; | ||
503 | for (int y = luy; y <= rly; y++) | ||
504 | for (int x = lux; x <= rlx; x++) | ||
505 | { | ||
506 | int len = 1; | ||
507 | disstrU[0] = fontMap(image[loc(x,y)].c); | ||
508 | int cf = image[loc(x,y)].f; | ||
509 | int cb = image[loc(x,y)].b; | ||
510 | int cr = image[loc(x,y)].r; | ||
511 | while (x+len <= rlx && | ||
512 | image[loc(x+len,y)].f == cf && | ||
513 | image[loc(x+len,y)].b == cb && | ||
514 | image[loc(x+len,y)].r == cr ) | ||
515 | { | ||
516 | disstrU[len] = fontMap(image[loc(x+len,y)].c); | ||
517 | len += 1; | ||
518 | } | ||
519 | QString unistr(disstrU,len); | ||
520 | drawAttrStr(paint, | ||
521 | QRect(blX+tLx+font_w*x,bY+tLy+font_h*y,font_w*len,font_h), | ||
522 | unistr, image[loc(x,y)], pm != NULL, false); | ||
523 | x += len - 1; | ||
524 | } | ||
525 | delete [] disstrU; | ||
526 | drawFrame( &paint ); | ||
527 | paint.end(); | ||
528 | setUpdatesEnabled(TRUE); | ||
529 | } | ||
530 | |||
531 | void TEWidget::blinkEvent() | ||
532 | { | ||
533 | blinking = !blinking; | ||
534 | repaint(FALSE); | ||
535 | } | ||
536 | |||
537 | /* ------------------------------------------------------------------------- */ | ||
538 | /* */ | ||
539 | /* Resizing */ | ||
540 | /* */ | ||
541 | /* ------------------------------------------------------------------------- */ | ||
542 | |||
543 | void TEWidget::resizeEvent(QResizeEvent* ev) | ||
544 | { | ||
545 | // printf("resize: %d,%d\n",ev->size().width(),ev->size().height()); | ||
546 | //printf("approx: %d,%d\n",ev->size().width()/font_w,ev->size().height()/font_h); | ||
547 | //printf("leaves: %d,%d\n",ev->size().width()%font_w,ev->size().height()%font_h); | ||
548 | //printf("curren: %d,%d\n",width(),height()); | ||
549 | HCNT("resizeEvent"); | ||
550 | |||
551 | // see comment in `paintEvent' concerning the rounding. | ||
552 | //FIXME: could make a routine here; check width(),height() | ||
553 | assert(ev->size().width() == width()); | ||
554 | assert(ev->size().height() == height()); | ||
555 | |||
556 | propagateSize(); | ||
557 | } | ||
558 | |||
559 | void TEWidget::propagateSize() | ||
560 | { | ||
561 | ca* oldimg = image; | ||
562 | int oldlin = lines; | ||
563 | int oldcol = columns; | ||
564 | makeImage(); | ||
565 | // we copy the old image to reduce flicker | ||
566 | int lins = QMIN(oldlin,lines); | ||
567 | int cols = QMIN(oldcol,columns); | ||
568 | if (oldimg) | ||
569 | { | ||
570 | for (int lin = 0; lin < lins; lin++) | ||
571 | memcpy((void*)&image[columns*lin], | ||
572 | (void*)&oldimg[oldcol*lin],cols*sizeof(ca)); | ||
573 | free(oldimg); //FIXME: try new,delete | ||
574 | } | ||
575 | else | ||
576 | clearImage(); | ||
577 | |||
578 | //NOTE: control flows from the back through the chest right into the eye. | ||
579 | // `emu' will call back via `setImage'. | ||
580 | |||
581 | resizing = TRUE; | ||
582 | emit changedImageSizeSignal(lines, columns); // expose resizeEvent | ||
583 | resizing = FALSE; | ||
584 | } | ||
585 | |||
586 | /* ------------------------------------------------------------------------- */ | ||
587 | /* */ | ||
588 | /* Scrollbar */ | ||
589 | /* */ | ||
590 | /* ------------------------------------------------------------------------- */ | ||
591 | |||
592 | void TEWidget::scrollChanged(int) | ||
593 | { | ||
594 | emit changedHistoryCursor(scrollbar->value()); //expose | ||
595 | } | ||
596 | |||
597 | void TEWidget::setScroll(int cursor, int slines) | ||
598 | { | ||
599 | disconnect(scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scrollChanged(int))); | ||
600 | scrollbar->setRange(0,slines); | ||
601 | scrollbar->setSteps(1,lines); | ||
602 | scrollbar->setValue(cursor); | ||
603 | connect(scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scrollChanged(int))); | ||
604 | } | ||
605 | |||
606 | void TEWidget::setScrollbarLocation(int loc) | ||
607 | { | ||
608 | if (scrollLoc == loc) return; // quickly | ||
609 | scrollLoc = loc; | ||
610 | propagateSize(); | ||
611 | update(); | ||
612 | } | ||
613 | |||
614 | /* ------------------------------------------------------------------------- */ | ||
615 | /* */ | ||
616 | /* Mouse */ | ||
617 | /* */ | ||
618 | /* ------------------------------------------------------------------------- */ | ||
619 | |||
620 | /*! | ||
621 | Three different operations can be performed using the mouse, and the | ||
622 | routines in this section serve all of them: | ||
623 | |||
624 | 1) The press/release events are exposed to the application | ||
625 | 2) Marking (press and move left button) and Pasting (press middle button) | ||
626 | 3) The right mouse button is used from the configuration menu | ||
627 | |||
628 | NOTE: During the marking process we attempt to keep the cursor within | ||
629 | the bounds of the text as being displayed by setting the mouse position | ||
630 | whenever the mouse has left the text area. | ||
631 | |||
632 | Two reasons to do so: | ||
633 | 1) QT does not allow the `grabMouse' to confine-to the TEWidget. | ||
634 | Thus a `XGrapPointer' would have to be used instead. | ||
635 | 2) Even if so, this would not help too much, since the text area | ||
636 | of the TEWidget is normally not identical with it's bounds. | ||
637 | |||
638 | The disadvantage of the current handling is, that the mouse can visibly | ||
639 | leave the bounds of the widget and is then moved back. Because of the | ||
640 | current construction, and the reasons mentioned above, we cannot do better | ||
641 | without changing the overall construction. | ||
642 | */ | ||
643 | |||
644 | /*! | ||
645 | */ | ||
646 | |||
647 | void TEWidget::mousePressEvent(QMouseEvent* ev) | ||
648 | { | ||
649 | //printf("press [%d,%d] %d\n",ev->x()/font_w,ev->y()/font_h,ev->button()); | ||
650 | if ( !contentsRect().contains(ev->pos()) ) return; | ||
651 | QPoint tL = contentsRect().topLeft(); | ||
652 | int tLx = tL.x(); | ||
653 | int tLy = tL.y(); | ||
654 | |||
655 | word_selection_mode = FALSE; | ||
656 | |||
657 | //printf("press top left [%d,%d] by=%d\n",tLx,tLy, bY); | ||
658 | if ( ev->button() == LeftButton) | ||
659 | { | ||
660 | QPoint pos = QPoint((ev->x()-tLx-blX)/font_w,(ev->y()-tLy-bY)/font_h); | ||
661 | |||
662 | if ( ev->state() & ControlButton ) preserve_line_breaks = FALSE ; | ||
663 | |||
664 | if (mouse_marks || (ev->state() & ShiftButton)) | ||
665 | { | ||
666 | emit clearSelectionSignal(); | ||
667 | iPntSel = pntSel = pos; | ||
668 | actSel = 1; // left mouse button pressed but nothing selected yet. | ||
669 | grabMouse( /*crossCursor*/ ); // handle with care! | ||
670 | } | ||
671 | else | ||
672 | { | ||
673 | emit mouseSignal( 0, pos.x() + 1, pos.y() + 1 ); // left button | ||
674 | } | ||
675 | } | ||
676 | if ( ev->button() == MidButton ) | ||
677 | { | ||
678 | emitSelection(); | ||
679 | } | ||
680 | if ( ev->button() == RightButton ) // Configure | ||
681 | { | ||
682 | emit configureRequest( this, ev->state()&(ShiftButton|ControlButton), ev->x(), ev->y() ); | ||
683 | } | ||
684 | } | ||
685 | |||
686 | void TEWidget::mouseMoveEvent(QMouseEvent* ev) | ||
687 | { | ||
688 | // for auto-hiding the cursor, we need mouseTracking | ||
689 | if (ev->state() == NoButton ) return; | ||
690 | |||
691 | if (actSel == 0) return; | ||
692 | |||
693 | // don't extend selection while pasting | ||
694 | if (ev->state() & MidButton) return; | ||
695 | |||
696 | //if ( !contentsRect().contains(ev->pos()) ) return; | ||
697 | QPoint tL = contentsRect().topLeft(); | ||
698 | int tLx = tL.x(); | ||
699 | int tLy = tL.y(); | ||
700 | int scroll = scrollbar->value(); | ||
701 | |||
702 | // we're in the process of moving the mouse with the left button pressed | ||
703 | // the mouse cursor will kept catched within the bounds of the text in | ||
704 | // this widget. | ||
705 | |||
706 | // Adjust position within text area bounds. See FIXME above. | ||
707 | QPoint pos = ev->pos(); | ||
708 | if ( pos.x() < tLx+blX ) pos.setX( tLx+blX ); | ||
709 | if ( pos.x() > tLx+blX+columns*font_w-1 ) pos.setX( tLx+blX+columns*font_w ); | ||
710 | if ( pos.y() < tLy+bY ) pos.setY( tLy+bY ); | ||
711 | if ( pos.y() > tLy+bY+lines*font_h-1 ) pos.setY( tLy+bY+lines*font_h-1 ); | ||
712 | // check if we produce a mouse move event by this | ||
713 | if ( pos != ev->pos() ) cursor().setPos(mapToGlobal(pos)); | ||
714 | |||
715 | if ( pos.y() == tLy+bY+lines*font_h-1 ) | ||
716 | { | ||
717 | scrollbar->setValue(scrollbar->value()+yMouseScroll); // scrollforward | ||
718 | } | ||
719 | if ( pos.y() == tLy+bY ) | ||
720 | { | ||
721 | scrollbar->setValue(scrollbar->value()-yMouseScroll); // scrollback | ||
722 | } | ||
723 | |||
724 | QPoint here = QPoint((pos.x()-tLx-blX)/font_w,(pos.y()-tLy-bY)/font_h); | ||
725 | QPoint ohere; | ||
726 | bool swapping = FALSE; | ||
727 | |||
728 | if ( word_selection_mode ) | ||
729 | { | ||
730 | // Extend to word boundaries | ||
731 | int i; | ||
732 | int selClass; | ||
733 | |||
734 | bool left_not_right = ( here.y() < iPntSel.y() || | ||
735 | here.y() == iPntSel.y() && here.x() < iPntSel.x() ); | ||
736 | bool old_left_not_right = ( pntSel.y() < iPntSel.y() || | ||
737 | pntSel.y() == iPntSel.y() && pntSel.x() < iPntSel.x() ); | ||
738 | swapping = left_not_right != old_left_not_right; | ||
739 | |||
740 | // Find left (left_not_right ? from here : from start) | ||
741 | QPoint left = left_not_right ? here : iPntSel; | ||
742 | i = loc(left.x(),left.y()); | ||
743 | selClass = charClass(image[i].c); | ||
744 | while ( left.x() > 0 && charClass(image[i-1].c) == selClass ) | ||
745 | { i--; left.rx()--; } | ||
746 | |||
747 | // Find left (left_not_right ? from start : from here) | ||
748 | QPoint right = left_not_right ? iPntSel : here; | ||
749 | i = loc(right.x(),right.y()); | ||
750 | selClass = charClass(image[i].c); | ||
751 | while ( right.x() < columns-1 && charClass(image[i+1].c) == selClass ) | ||
752 | { i++; right.rx()++; } | ||
753 | |||
754 | // Pick which is start (ohere) and which is extension (here) | ||
755 | if ( left_not_right ) | ||
756 | { | ||
757 | here = left; ohere = right; | ||
758 | } | ||
759 | else | ||
760 | { | ||
761 | here = right; ohere = left; | ||
762 | } | ||
763 | } | ||
764 | |||
765 | if (here == pntSel && scroll == scrollbar->value()) return; // not moved | ||
766 | |||
767 | if ( word_selection_mode ) { | ||
768 | if ( actSel < 2 || swapping ) { | ||
769 | emit beginSelectionSignal( ohere.x(), ohere.y() ); | ||
770 | } | ||
771 | } else if ( actSel < 2 ) { | ||
772 | emit beginSelectionSignal( pntSel.x(), pntSel.y() ); | ||
773 | } | ||
774 | |||
775 | actSel = 2; // within selection | ||
776 | pntSel = here; | ||
777 | emit extendSelectionSignal( here.x(), here.y() ); | ||
778 | } | ||
779 | |||
780 | void TEWidget::mouseReleaseEvent(QMouseEvent* ev) | ||
781 | { | ||
782 | //printf("release [%d,%d] %d\n",ev->x()/font_w,ev->y()/font_h,ev->button()); | ||
783 | if ( ev->button() == LeftButton) | ||
784 | { | ||
785 | if ( actSel > 1 ) emit endSelectionSignal(preserve_line_breaks); | ||
786 | preserve_line_breaks = TRUE; | ||
787 | actSel = 0; | ||
788 | |||
789 | //FIXME: emits a release event even if the mouse is | ||
790 | // outside the range. The procedure used in `mouseMoveEvent' | ||
791 | // applies here, too. | ||
792 | |||
793 | QPoint tL = contentsRect().topLeft(); | ||
794 | int tLx = tL.x(); | ||
795 | int tLy = tL.y(); | ||
796 | |||
797 | if (!mouse_marks && !(ev->state() & ShiftButton)) | ||
798 | emit mouseSignal( 3, // release | ||
799 | (ev->x()-tLx-blX)/font_w + 1, | ||
800 | (ev->y()-tLy-bY)/font_h + 1 ); | ||
801 | releaseMouse(); | ||
802 | } | ||
803 | } | ||
804 | |||
805 | void TEWidget::mouseDoubleClickEvent(QMouseEvent* ev) | ||
806 | { | ||
807 | if ( ev->button() != LeftButton) return; | ||
808 | |||
809 | QPoint tL = contentsRect().topLeft(); | ||
810 | int tLx = tL.x(); | ||
811 | int tLy = tL.y(); | ||
812 | QPoint pos = QPoint((ev->x()-tLx-blX)/font_w,(ev->y()-tLy-bY)/font_h); | ||
813 | |||
814 | // pass on double click as two clicks. | ||
815 | if (!mouse_marks && !(ev->state() & ShiftButton)) | ||
816 | { | ||
817 | emit mouseSignal( 0, pos.x()+1, pos.y()+1 ); // left button | ||
818 | emit mouseSignal( 3, pos.x()+1, pos.y()+1 ); // release | ||
819 | emit mouseSignal( 0, pos.x()+1, pos.y()+1 ); // left button | ||
820 | return; | ||
821 | } | ||
822 | |||
823 | |||
824 | emit clearSelectionSignal(); | ||
825 | QPoint bgnSel = pos; | ||
826 | QPoint endSel = QPoint((ev->x()-tLx-blX)/font_w,(ev->y()-tLy-bY)/font_h); | ||
827 | int i = loc(bgnSel.x(),bgnSel.y()); | ||
828 | iPntSel = bgnSel; | ||
829 | |||
830 | word_selection_mode = TRUE; | ||
831 | |||
832 | // find word boundaries... | ||
833 | int selClass = charClass(image[i].c); | ||
834 | { | ||
835 | // set the start... | ||
836 | int x = bgnSel.x(); | ||
837 | while ( x > 0 && charClass(image[i-1].c) == selClass ) | ||
838 | { i--; x--; } | ||
839 | bgnSel.setX(x); | ||
840 | emit beginSelectionSignal( bgnSel.x(), bgnSel.y() ); | ||
841 | |||
842 | // set the end... | ||
843 | i = loc( endSel.x(), endSel.y() ); | ||
844 | x = endSel.x(); | ||
845 | while( x < columns-1 && charClass(image[i+1].c) == selClass ) | ||
846 | { i++; x++ ; } | ||
847 | endSel.setX(x); | ||
848 | actSel = 2; // within selection | ||
849 | emit extendSelectionSignal( endSel.x(), endSel.y() ); | ||
850 | emit endSelectionSignal(preserve_line_breaks); | ||
851 | preserve_line_breaks = TRUE; | ||
852 | } | ||
853 | } | ||
854 | |||
855 | void TEWidget::focusInEvent( QFocusEvent * ) | ||
856 | { | ||
857 | |||
858 | // do nothing, to prevent repainting | ||
859 | } | ||
860 | |||
861 | |||
862 | void TEWidget::focusOutEvent( QFocusEvent * ) | ||
863 | { | ||
864 | // do nothing, to prevent repainting | ||
865 | } | ||
866 | |||
867 | bool TEWidget::focusNextPrevChild( bool next ) | ||
868 | { | ||
869 | if (next) | ||
870 | return false; // This disables changing the active part in konqueror | ||
871 | // when pressing Tab | ||
872 | return QFrame::focusNextPrevChild( next ); | ||
873 | } | ||
874 | |||
875 | |||
876 | int TEWidget::charClass(char ch) const | ||
877 | { | ||
878 | // This might seem like overkill, but imagine if ch was a Unicode | ||
879 | // character (Qt 2.0 QChar) - it might then be sensible to separate | ||
880 | // the different language ranges, etc. | ||
881 | |||
882 | if ( isspace(ch) ) return ' '; | ||
883 | |||
884 | static const char *word_characters = ":@-./_~"; | ||
885 | if ( isalnum(ch) || strchr(word_characters, ch) ) | ||
886 | return 'a'; | ||
887 | |||
888 | // Everything else is weird | ||
889 | return 1; | ||
890 | } | ||
891 | |||
892 | void TEWidget::setMouseMarks(bool on) | ||
893 | { | ||
894 | mouse_marks = on; | ||
895 | setCursor( mouse_marks ? ibeamCursor : arrowCursor ); | ||
896 | } | ||
897 | |||
898 | /* ------------------------------------------------------------------------- */ | ||
899 | /* */ | ||
900 | /* Clipboard */ | ||
901 | /* */ | ||
902 | /* ------------------------------------------------------------------------- */ | ||
903 | |||
904 | #undef KeyPress | ||
905 | |||
906 | void TEWidget::emitSelection() | ||
907 | // Paste Clipboard by simulating keypress events | ||
908 | { | ||
909 | #ifndef QT_NO_CLIPBOARD | ||
910 | QString text = QApplication::clipboard()->text(); | ||
911 | if ( ! text.isNull() ) | ||
912 | { | ||
913 | text.replace(QRegExp("\n"), "\r"); | ||
914 | QKeyEvent e(QEvent::KeyPress, 0, -1, 0, text); | ||
915 | emit keyPressedSignal(&e); // expose as a big fat keypress event | ||
916 | emit clearSelectionSignal(); | ||
917 | } | ||
918 | #endif | ||
919 | } | ||
920 | |||
921 | void TEWidget::emitText(QString text) | ||
922 | { | ||
923 | QKeyEvent e(QEvent::KeyPress, 0, -1, 0, text); | ||
924 | emit keyPressedSignal(&e); // expose as a big fat keypress event | ||
925 | } | ||
926 | |||
927 | void TEWidget::pasteClipboard( ) | ||
928 | { | ||
929 | emitSelection(); | ||
930 | } | ||
931 | |||
932 | void TEWidget::setSelection(const QString& t) | ||
933 | { | ||
934 | #ifndef QT_NO_CLIPBOARD | ||
935 | // Disconnect signal while WE set the clipboard | ||
936 | QObject *cb = QApplication::clipboard(); | ||
937 | QObject::disconnect( cb, SIGNAL(dataChanged()), | ||
938 | this, SLOT(onClearSelection()) ); | ||
939 | |||
940 | QApplication::clipboard()->setText(t); | ||
941 | |||
942 | QObject::connect( cb, SIGNAL(dataChanged()), | ||
943 | this, SLOT(onClearSelection()) ); | ||
944 | #endif | ||
945 | } | ||
946 | |||
947 | void TEWidget::onClearSelection() | ||
948 | { | ||
949 | emit clearSelectionSignal(); | ||
950 | } | ||
951 | |||
952 | /* ------------------------------------------------------------------------- */ | ||
953 | /* */ | ||
954 | /* Keyboard */ | ||
955 | /* */ | ||
956 | /* ------------------------------------------------------------------------- */ | ||
957 | |||
958 | //FIXME: an `eventFilter' has been installed instead of a `keyPressEvent' | ||
959 | // due to a bug in `QT' or the ignorance of the author to prevent | ||
960 | // repaint events being emitted to the screen whenever one leaves | ||
961 | // or reenters the screen to/from another application. | ||
962 | // | ||
963 | // Troll says one needs to change focusInEvent() and focusOutEvent(), | ||
964 | // which would also let you have an in-focus cursor and an out-focus | ||
965 | // cursor like xterm does. | ||
966 | |||
967 | // for the auto-hide cursor feature, I added empty focusInEvent() and | ||
968 | // focusOutEvent() so that update() isn't called. | ||
969 | // For auto-hide, we need to get keypress-events, but we only get them when | ||
970 | // we have focus. | ||
971 | |||
972 | void TEWidget::doScroll(int lines) | ||
973 | { | ||
974 | scrollbar->setValue(scrollbar->value()+lines); | ||
975 | } | ||
976 | |||
977 | bool TEWidget::eventFilter( QObject *obj, QEvent *e ) | ||
978 | { | ||
979 | if ( (e->type() == QEvent::Accel || | ||
980 | e->type() == QEvent::AccelAvailable ) && qApp->focusWidget() == this ) { | ||
981 | static_cast<QKeyEvent *>( e )->ignore(); | ||
982 | return true; | ||
983 | } | ||
984 | if ( obj != this /* when embedded */ && obj != parent() /* when standalone */ ) | ||
985 | return FALSE; // not us | ||
986 | if ( e->type() == QEvent::Wheel) { | ||
987 | QApplication::sendEvent(scrollbar, e); | ||
988 | } | ||
989 | |||
990 | #ifdef FAKE_CTRL_AND_ALT | ||
991 | static bool control = FALSE; | ||
992 | static bool alt = FALSE; | ||
993 | // qDebug(" Has a keyboard with no CTRL and ALT keys, but we fake it:"); | ||
994 | bool dele=FALSE; | ||
995 | if ( e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease ) { | ||
996 | QKeyEvent* ke = (QKeyEvent*)e; | ||
997 | bool keydown = e->type() == QEvent::KeyPress || ke->isAutoRepeat(); | ||
998 | switch (ke->key()) { | ||
999 | case Key_F9: // let this be "Control" | ||
1000 | control = keydown; | ||
1001 | e = new QKeyEvent(QEvent::KeyPress, Key_Control, 0, ke->state()); | ||
1002 | dele=TRUE; | ||
1003 | break; | ||
1004 | case Key_F13: // let this be "Alt" | ||
1005 | alt = keydown; | ||
1006 | e = new QKeyEvent(QEvent::KeyPress, Key_Alt, 0, ke->state()); | ||
1007 | dele=TRUE; | ||
1008 | break; | ||
1009 | default: | ||
1010 | if ( control ) { | ||
1011 | int a = toupper(ke->ascii())-64; | ||
1012 | if ( a >= 0 && a < ' ' ) { | ||
1013 | e = new QKeyEvent(e->type(), ke->key(), | ||
1014 | a, ke->state()|ControlButton, QChar(a,0)); | ||
1015 | dele=TRUE; | ||
1016 | } | ||
1017 | } | ||
1018 | if ( alt ) { | ||
1019 | e = new QKeyEvent(e->type(), ke->key(), | ||
1020 | ke->ascii(), ke->state()|AltButton, ke->text()); | ||
1021 | dele=TRUE; | ||
1022 | } | ||
1023 | } | ||
1024 | } | ||
1025 | #endif | ||
1026 | |||
1027 | if ( e->type() == QEvent::KeyPress ) { | ||
1028 | QKeyEvent* ke = (QKeyEvent*)e; | ||
1029 | actSel=0; // Key stroke implies a screen update, so TEWidget won't | ||
1030 | // know where the current selection is. | ||
1031 | |||
1032 | // qDebug("key pressed is 0x%x",ke->key()); | ||
1033 | |||
1034 | if( ke->state() == ShiftButton && ke->key() == Key_Tab) { //lets hardcode this sucker | ||
1035 | |||
1036 | // qDebug("key pressed 2 is 0x%x",ke->key()); | ||
1037 | emitText("\\"); // expose | ||
1038 | } else | ||
1039 | emit keyPressedSignal(ke); // expose | ||
1040 | ke->accept(); | ||
1041 | #ifdef FAKE_CTRL_AND_ALT | ||
1042 | if ( dele ) delete e; | ||
1043 | #endif | ||
1044 | return true; // stop the event | ||
1045 | } | ||
1046 | if ( e->type() == QEvent::Enter ) { | ||
1047 | QObject::disconnect( (QObject*)cb, SIGNAL(dataChanged()), | ||
1048 | this, SLOT(onClearSelection()) ); | ||
1049 | } | ||
1050 | if ( e->type() == QEvent::Leave ) { | ||
1051 | QObject::connect( (QObject*)cb, SIGNAL(dataChanged()), | ||
1052 | this, SLOT(onClearSelection()) ); | ||
1053 | } | ||
1054 | return QFrame::eventFilter( obj, e ); | ||
1055 | } | ||
1056 | |||
1057 | /* ------------------------------------------------------------------------- */ | ||
1058 | /* */ | ||
1059 | /* Frame */ | ||
1060 | /* */ | ||
1061 | /* ------------------------------------------------------------------------- */ | ||
1062 | |||
1063 | void TEWidget::frameChanged() | ||
1064 | { | ||
1065 | propagateSize(); | ||
1066 | update(); | ||
1067 | } | ||
1068 | |||
1069 | /* ------------------------------------------------------------------------- */ | ||
1070 | /* */ | ||
1071 | /* Sound */ | ||
1072 | /* */ | ||
1073 | /* ------------------------------------------------------------------------- */ | ||
1074 | |||
1075 | void TEWidget::Bell() | ||
1076 | { | ||
1077 | QApplication::beep(); | ||
1078 | } | ||
1079 | |||
1080 | /* ------------------------------------------------------------------------- */ | ||
1081 | /* */ | ||
1082 | /* Auxiluary */ | ||
1083 | /* */ | ||
1084 | /* ------------------------------------------------------------------------- */ | ||
1085 | |||
1086 | void TEWidget::clearImage() | ||
1087 | // initialize the image | ||
1088 | // for internal use only | ||
1089 | { | ||
1090 | for (int y = 0; y < lines; y++) | ||
1091 | for (int x = 0; x < columns; x++) | ||
1092 | { | ||
1093 | image[loc(x,y)].c = 0xff; //' '; | ||
1094 | image[loc(x,y)].f = 0xff; //DEFAULT_FORE_COLOR; | ||
1095 | image[loc(x,y)].b = 0xff; //DEFAULT_BACK_COLOR; | ||
1096 | image[loc(x,y)].r = 0xff; //DEFAULT_RENDITION; | ||
1097 | } | ||
1098 | } | ||
1099 | |||
1100 | // Create Image /////////////////////////////////////////////////////// | ||
1101 | |||
1102 | void TEWidget::calcGeometry() | ||
1103 | { | ||
1104 | //FIXME: set rimX == rimY == 0 when running in full screen mode. | ||
1105 | |||
1106 | scrollbar->resize(QApplication::style().scrollBarExtent().width(), | ||
1107 | contentsRect().height()); | ||
1108 | switch(scrollLoc) | ||
1109 | { | ||
1110 | case SCRNONE : | ||
1111 | columns = ( contentsRect().width() - 2 * rimX ) / font_w; | ||
1112 | blX = (contentsRect().width() - (columns*font_w) ) / 2; | ||
1113 | brX = blX; | ||
1114 | scrollbar->hide(); | ||
1115 | break; | ||
1116 | case SCRLEFT : | ||
1117 | columns = ( contentsRect().width() - 2 * rimX - scrollbar->width()) / font_w; | ||
1118 | brX = (contentsRect().width() - (columns*font_w) - scrollbar->width() ) / 2; | ||
1119 | blX = brX + scrollbar->width(); | ||
1120 | scrollbar->move(contentsRect().topLeft()); | ||
1121 | scrollbar->show(); | ||
1122 | break; | ||
1123 | case SCRRIGHT: | ||
1124 | columns = ( contentsRect().width() - 2 * rimX - scrollbar->width()) / font_w; | ||
1125 | blX = (contentsRect().width() - (columns*font_w) - scrollbar->width() ) / 2; | ||
1126 | brX = blX; | ||
1127 | scrollbar->move(contentsRect().topRight() - QPoint(scrollbar->width()-1,0)); | ||
1128 | scrollbar->show(); | ||
1129 | break; | ||
1130 | } | ||
1131 | //FIXME: support 'rounding' styles | ||
1132 | lines = ( contentsRect().height() - 2 * rimY ) / font_h; | ||
1133 | bY = (contentsRect().height() - (lines *font_h)) / 2; | ||
1134 | } | ||
1135 | |||
1136 | void TEWidget::makeImage() | ||
1137 | //FIXME: rename 'calcGeometry? | ||
1138 | { | ||
1139 | calcGeometry(); | ||
1140 | image = (ca*) malloc(lines*columns*sizeof(ca)); | ||
1141 | clearImage(); | ||
1142 | } | ||
1143 | |||
1144 | // calculate the needed size | ||
1145 | QSize TEWidget::calcSize(int cols, int lins) const | ||
1146 | { | ||
1147 | int frw = width() - contentsRect().width(); | ||
1148 | int frh = height() - contentsRect().height(); | ||
1149 | int scw = (scrollLoc==SCRNONE?0:scrollbar->width()); | ||
1150 | return QSize( font_w*cols + 2*rimX + frw + scw, font_h*lins + 2*rimY + frh ); | ||
1151 | } | ||
1152 | |||
1153 | QSize TEWidget::sizeHint() const | ||
1154 | { | ||
1155 | return size(); | ||
1156 | } | ||
1157 | |||
1158 | void TEWidget::styleChange(QStyle &) | ||
1159 | { | ||
1160 | propagateSize(); | ||
1161 | } | ||
1162 | |||
1163 | #ifndef QT_NO_DRAGANDDROP | ||
1164 | |||
1165 | /* --------------------------------------------------------------------- */ | ||
1166 | /* */ | ||
1167 | /* Drag & Drop */ | ||
1168 | /* */ | ||
1169 | /* --------------------------------------------------------------------- */ | ||
1170 | |||
1171 | |||
1172 | void TEWidget::dragEnterEvent(QDragEnterEvent* e) | ||
1173 | { | ||
1174 | e->accept(QTextDrag::canDecode(e) || | ||
1175 | QUriDrag::canDecode(e)); | ||
1176 | } | ||
1177 | |||
1178 | void TEWidget::dropEvent(QDropEvent* event) | ||
1179 | { | ||
1180 | // The current behaviour when url(s) are dropped is | ||
1181 | // * if there is only ONE url and if it's a LOCAL one, ask for paste or cd | ||
1182 | // * in all other cases, just paste | ||
1183 | // (for non-local ones, or for a list of URLs, 'cd' is nonsense) | ||
1184 | QStrList strlist; | ||
1185 | int file_count = 0; | ||
1186 | dropText = ""; | ||
1187 | bool bPopup = true; | ||
1188 | |||
1189 | if(QUriDrag::decode(event, strlist)) { | ||
1190 | if (strlist.count()) { | ||
1191 | for(const char* p = strlist.first(); p; p = strlist.next()) { | ||
1192 | if(file_count++ > 0) { | ||
1193 | dropText += " "; | ||
1194 | bPopup = false; // more than one file, don't popup | ||
1195 | } | ||
1196 | |||
1197 | /* | ||
1198 | KURL url(p); | ||
1199 | if (url.isLocalFile()) { | ||
1200 | dropText += url.path(); // local URL : remove protocol | ||
1201 | } | ||
1202 | else { | ||
1203 | dropText += url.prettyURL(); | ||
1204 | bPopup = false; // a non-local file, don't popup | ||
1205 | } | ||
1206 | */ | ||
1207 | |||
1208 | } | ||
1209 | |||
1210 | if (bPopup) | ||
1211 | // m_drop->popup(pos() + event->pos()); | ||
1212 | m_drop->popup(mapToGlobal(event->pos())); | ||
1213 | else | ||
1214 | { | ||
1215 | if (currentSession) { | ||
1216 | currentSession->getEmulation()->sendString(dropText.local8Bit()); | ||
1217 | } | ||
1218 | // kdDebug() << "Drop:" << dropText.local8Bit() << "\n"; | ||
1219 | } | ||
1220 | } | ||
1221 | } | ||
1222 | else if(QTextDrag::decode(event, dropText)) { | ||
1223 | // kdDebug() << "Drop:" << dropText.local8Bit() << "\n"; | ||
1224 | if (currentSession) { | ||
1225 | currentSession->getEmulation()->sendString(dropText.local8Bit()); | ||
1226 | } | ||
1227 | // Paste it | ||
1228 | } | ||
1229 | } | ||
1230 | #endif | ||
1231 | |||
1232 | |||
1233 | void TEWidget::drop_menu_activated(int item) | ||
1234 | { | ||
1235 | #ifndef QT_NO_DRAGANDDROP | ||
1236 | switch (item) | ||
1237 | { | ||
1238 | case 0: // paste | ||
1239 | currentSession->getEmulation()->sendString(dropText.local8Bit()); | ||
1240 | // KWM::activate((Window)this->winId()); | ||
1241 | break; | ||
1242 | case 1: // cd ... | ||
1243 | currentSession->getEmulation()->sendString("cd "); | ||
1244 | struct stat statbuf; | ||
1245 | if ( ::stat( QFile::encodeName( dropText ), &statbuf ) == 0 ) | ||
1246 | { | ||
1247 | if ( !S_ISDIR(statbuf.st_mode) ) | ||
1248 | { | ||
1249 | /* | ||
1250 | KURL url; | ||
1251 | url.setPath( dropText ); | ||
1252 | dropText = url.directory( true, false ); // remove filename | ||
1253 | */ | ||
1254 | } | ||
1255 | } | ||
1256 | dropText.replace(QRegExp(" "), "\\ "); // escape spaces | ||
1257 | currentSession->getEmulation()->sendString(dropText.local8Bit()); | ||
1258 | currentSession->getEmulation()->sendString("\n"); | ||
1259 | // KWM::activate((Window)this->winId()); | ||
1260 | break; | ||
1261 | } | ||
1262 | #endif | ||
1263 | } | ||
1264 | |||