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