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