Mercurial > hg > octave-lyh
comparison gui/src/terminal/TerminalDisplay.cpp @ 13506:c70511cf64ee
Reformatted to GNU Style.
author | Jacob Dawid <jacob.dawid@googlemail.com> |
---|---|
date | Sun, 17 Jul 2011 22:59:28 +0200 |
parents | 86d6c3b90ad7 |
children | 7eb8cd35454c |
comparison
equal
deleted
inserted
replaced
13505:3a26a0ad2df9 | 13506:c70511cf64ee |
---|---|
60 const ColorEntry base_color_table[TABLE_COLORS] = | 60 const ColorEntry base_color_table[TABLE_COLORS] = |
61 // The following are almost IBM standard color codes, with some slight | 61 // The following are almost IBM standard color codes, with some slight |
62 // gamma correction for the dim colors to compensate for bright X screens. | 62 // gamma correction for the dim colors to compensate for bright X screens. |
63 // It contains the 8 ansiterm/xterm colors in 2 intensities. | 63 // It contains the 8 ansiterm/xterm colors in 2 intensities. |
64 { | 64 { |
65 // Fixme: could add faint colors here, also. | 65 // Fixme: could add faint colors here, also. |
66 // normal | 66 // normal |
67 ColorEntry(QColor(0x00,0x00,0x00), 0), ColorEntry( QColor(0xB2,0xB2,0xB2), 1), // Dfore, Dback | 67 ColorEntry (QColor (0x00, 0x00, 0x00), 0), ColorEntry (QColor (0xB2, 0xB2, 0xB2), 1), // Dfore, Dback |
68 ColorEntry(QColor(0x00,0x00,0x00), 0), ColorEntry( QColor(0xB2,0x18,0x18), 0), // Black, Red | 68 ColorEntry (QColor (0x00, 0x00, 0x00), 0), ColorEntry (QColor (0xB2, 0x18, 0x18), 0), // Black, Red |
69 ColorEntry(QColor(0x18,0xB2,0x18), 0), ColorEntry( QColor(0xB2,0x68,0x18), 0), // Green, Yellow | 69 ColorEntry (QColor (0x18, 0xB2, 0x18), 0), ColorEntry (QColor (0xB2, 0x68, 0x18), 0), // Green, Yellow |
70 ColorEntry(QColor(0x18,0x18,0xB2), 0), ColorEntry( QColor(0xB2,0x18,0xB2), 0), // Blue, Magenta | 70 ColorEntry (QColor (0x18, 0x18, 0xB2), 0), ColorEntry (QColor (0xB2, 0x18, 0xB2), 0), // Blue, Magenta |
71 ColorEntry(QColor(0x18,0xB2,0xB2), 0), ColorEntry( QColor(0xB2,0xB2,0xB2), 0), // Cyan, White | 71 ColorEntry (QColor (0x18, 0xB2, 0xB2), 0), ColorEntry (QColor (0xB2, 0xB2, 0xB2), 0), // Cyan, White |
72 // intensiv | 72 // intensiv |
73 ColorEntry(QColor(0x00,0x00,0x00), 0), ColorEntry( QColor(0xFF,0xFF,0xFF), 1), | 73 ColorEntry (QColor (0x00, 0x00, 0x00), 0), |
74 ColorEntry(QColor(0x68,0x68,0x68), 0), ColorEntry( QColor(0xFF,0x54,0x54), 0), | 74 ColorEntry (QColor (0xFF, 0xFF, 0xFF), 1), |
75 ColorEntry(QColor(0x54,0xFF,0x54), 0), ColorEntry( QColor(0xFF,0xFF,0x54), 0), | 75 ColorEntry (QColor (0x68, 0x68, 0x68), 0), |
76 ColorEntry(QColor(0x54,0x54,0xFF), 0), ColorEntry( QColor(0xFF,0x54,0xFF), 0), | 76 ColorEntry (QColor (0xFF, 0x54, 0x54), 0), |
77 ColorEntry(QColor(0x54,0xFF,0xFF), 0), ColorEntry( QColor(0xFF,0xFF,0xFF), 0) | 77 ColorEntry (QColor (0x54, 0xFF, 0x54), 0), |
78 ColorEntry (QColor (0xFF, 0xFF, 0x54), 0), | |
79 ColorEntry (QColor (0x54, 0x54, 0xFF), 0), | |
80 ColorEntry (QColor (0xFF, 0x54, 0xFF), 0), | |
81 ColorEntry (QColor (0x54, 0xFF, 0xFF), 0), | |
82 ColorEntry (QColor (0xFF, 0xFF, 0xFF), 0) | |
78 }; | 83 }; |
79 | 84 |
80 // scroll increment used when dragging selection at top/bottom of window. | 85 // scroll increment used when dragging selection at top/bottom of window. |
81 | 86 |
82 // static | 87 // static |
83 bool TerminalDisplay::_antialiasText = true; | 88 bool |
84 bool TerminalDisplay::HAVE_TRANSPARENCY = false; | 89 TerminalDisplay::_antialiasText = true; |
90 bool | |
91 TerminalDisplay::HAVE_TRANSPARENCY = false; | |
85 | 92 |
86 // we use this to force QPainter to display text in LTR mode | 93 // we use this to force QPainter to display text in LTR mode |
87 // more information can be found in: http://unicode.org/reports/tr9/ | 94 // more information can be found in: http://unicode.org/reports/tr9/ |
88 const QChar LTR_OVERRIDE_CHAR( 0x202D ); | 95 const QChar |
96 LTR_OVERRIDE_CHAR (0x202D); | |
89 | 97 |
90 /* ------------------------------------------------------------------------- */ | 98 /* ------------------------------------------------------------------------- */ |
91 /* */ | 99 /* */ |
92 /* Colors */ | 100 /* Colors */ |
93 /* */ | 101 /* */ |
99 ----------- ------- ------- ------- ------- ------- ------- ------- ------- | 107 ----------- ------- ------- ------- ------- ------- ------- ------- ------- |
100 ANSI (bgr) Black Red Green Yellow Blue Magenta Cyan White | 108 ANSI (bgr) Black Red Green Yellow Blue Magenta Cyan White |
101 IBMPC (rgb) Black Blue Green Cyan Red Magenta Yellow White | 109 IBMPC (rgb) Black Blue Green Cyan Red Magenta Yellow White |
102 */ | 110 */ |
103 | 111 |
104 ScreenWindow* TerminalDisplay::screenWindow() const | 112 ScreenWindow * |
105 { | 113 TerminalDisplay::screenWindow () const |
106 return _screenWindow; | 114 { |
107 } | 115 return _screenWindow; |
108 void TerminalDisplay::setScreenWindow(ScreenWindow* window) | 116 } |
109 { | 117 |
110 // disconnect existing screen window if any | 118 void |
111 if ( _screenWindow ) | 119 TerminalDisplay::setScreenWindow (ScreenWindow * window) |
112 { | 120 { |
113 disconnect( _screenWindow , 0 , this , 0 ); | 121 // disconnect existing screen window if any |
114 } | 122 if (_screenWindow) |
115 | 123 { |
116 _screenWindow = window; | 124 disconnect (_screenWindow, 0, this, 0); |
117 | 125 } |
118 if ( window ) | 126 |
119 { | 127 _screenWindow = window; |
120 | 128 |
121 // TODO: Determine if this is an issue. | 129 if (window) |
122 //#warning "The order here is not specified - does it matter whether updateImage or updateLineProperties comes first?" | 130 { |
123 connect( _screenWindow , SIGNAL(outputChanged()) , this , SLOT(updateLineProperties()) ); | 131 |
124 connect( _screenWindow , SIGNAL(outputChanged()) , this , SLOT(updateImage()) ); | 132 // TODO: Determine if this is an issue. |
125 window->setWindowLines(_lines); | 133 //#warning "The order here is not specified - does it matter whether updateImage or updateLineProperties comes first?" |
126 } | 134 connect (_screenWindow, SIGNAL (outputChanged ()), this, |
127 } | 135 SLOT (updateLineProperties ())); |
128 | 136 connect (_screenWindow, SIGNAL (outputChanged ()), this, |
129 const ColorEntry* TerminalDisplay::colorTable() const | 137 SLOT (updateImage ())); |
130 { | 138 window->setWindowLines (_lines); |
131 return _colorTable; | 139 } |
132 } | 140 } |
133 void TerminalDisplay::setBackgroundColor(const QColor& color) | 141 |
134 { | 142 const ColorEntry * |
135 _colorTable[DEFAULT_BACK_COLOR].color = color; | 143 TerminalDisplay::colorTable () const |
136 QPalette p = palette(); | 144 { |
137 p.setColor( backgroundRole(), color ); | 145 return _colorTable; |
138 setPalette( p ); | 146 } |
139 | 147 |
140 // Avoid propagating the palette change to the scroll bar | 148 void |
141 _scrollBar->setPalette( QApplication::palette() ); | 149 TerminalDisplay::setBackgroundColor (const QColor & color) |
142 | 150 { |
143 update(); | 151 _colorTable[DEFAULT_BACK_COLOR].color = color; |
144 } | 152 QPalette p = palette (); |
145 void TerminalDisplay::setForegroundColor(const QColor& color) | 153 p.setColor (backgroundRole (), color); |
146 { | 154 setPalette (p); |
147 _colorTable[DEFAULT_FORE_COLOR].color = color; | 155 |
148 | 156 // Avoid propagating the palette change to the scroll bar |
149 update(); | 157 _scrollBar->setPalette (QApplication::palette ()); |
150 } | 158 |
151 void TerminalDisplay::setColorTable(const ColorEntry table[]) | 159 update (); |
152 { | 160 } |
153 for (int i = 0; i < TABLE_COLORS; i++) | 161 |
154 _colorTable[i] = table[i]; | 162 void |
155 | 163 TerminalDisplay::setForegroundColor (const QColor & color) |
156 setBackgroundColor(_colorTable[DEFAULT_BACK_COLOR].color); | 164 { |
165 _colorTable[DEFAULT_FORE_COLOR].color = color; | |
166 | |
167 update (); | |
168 } | |
169 | |
170 void | |
171 TerminalDisplay::setColorTable (const ColorEntry table[]) | |
172 { | |
173 for (int i = 0; i < TABLE_COLORS; i++) | |
174 _colorTable[i] = table[i]; | |
175 | |
176 setBackgroundColor (_colorTable[DEFAULT_BACK_COLOR].color); | |
157 } | 177 } |
158 | 178 |
159 /* ------------------------------------------------------------------------- */ | 179 /* ------------------------------------------------------------------------- */ |
160 /* */ | 180 /* */ |
161 /* Font */ | 181 /* Font */ |
172 We treat non-iso10646 fonts as VT100 extended and do the requiered mapping | 192 We treat non-iso10646 fonts as VT100 extended and do the requiered mapping |
173 from unicode to 0x00..0x1f. The remaining translation is then left to the | 193 from unicode to 0x00..0x1f. The remaining translation is then left to the |
174 QCodec. | 194 QCodec. |
175 */ | 195 */ |
176 | 196 |
177 static inline bool isLineChar(quint16 c) { return ((c & 0xFF80) == 0x2500);} | 197 static inline bool |
178 static inline bool isLineCharString(const QString& string) | 198 isLineChar (quint16 c) |
179 { | 199 { |
180 return (string.length() > 0) && (isLineChar(string.at(0).unicode())); | 200 return ((c & 0xFF80) == 0x2500); |
201 } | |
202 | |
203 static inline bool | |
204 isLineCharString (const QString & string) | |
205 { | |
206 return (string.length () > 0) && (isLineChar (string.at (0).unicode ())); | |
181 } | 207 } |
182 | 208 |
183 | 209 |
184 // assert for i in [0..31] : vt100extended(vt100_graphics[i]) == i. | 210 // assert for i in [0..31] : vt100extended(vt100_graphics[i]) == i. |
185 | 211 |
186 unsigned short vt100_graphics[32] = | 212 unsigned short vt100_graphics[32] = { // 0/8 1/9 2/10 3/11 4/12 5/13 6/14 7/15 |
187 { // 0/8 1/9 2/10 3/11 4/12 5/13 6/14 7/15 | |
188 0x0020, 0x25C6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, | 213 0x0020, 0x25C6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, |
189 0x00b1, 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, | 214 0x00b1, 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, |
190 0xF800, 0xF801, 0x2500, 0xF803, 0xF804, 0x251c, 0x2524, 0x2534, | 215 0xF800, 0xF801, 0x2500, 0xF803, 0xF804, 0x251c, 0x2524, 0x2534, |
191 0x252c, 0x2502, 0x2264, 0x2265, 0x03C0, 0x2260, 0x00A3, 0x00b7 | 216 0x252c, 0x2502, 0x2264, 0x2265, 0x03C0, 0x2260, 0x00A3, 0x00b7 |
192 }; | 217 }; |
193 | 218 |
194 void TerminalDisplay::fontChange(const QFont&) | 219 void |
195 { | 220 TerminalDisplay::fontChange (const QFont &) |
196 QFontMetrics fm(font()); | 221 { |
197 _fontHeight = fm.height() + _lineSpacing; | 222 QFontMetrics fm (font ()); |
198 | 223 _fontHeight = fm.height () + _lineSpacing; |
199 // waba TerminalDisplay 1.123: | 224 |
200 // "Base character width on widest ASCII character. This prevents too wide | 225 // waba TerminalDisplay 1.123: |
201 // characters in the presence of double wide (e.g. Japanese) characters." | 226 // "Base character width on widest ASCII character. This prevents too wide |
202 // Get the width from representative normal width characters | 227 // characters in the presence of double wide (e.g. Japanese) characters." |
203 _fontWidth = qRound((double)fm.width(REPCHAR)/(double)strlen(REPCHAR)); | 228 // Get the width from representative normal width characters |
204 | 229 _fontWidth = |
205 _fixedFont = true; | 230 qRound ((double) fm.width (REPCHAR) / (double) strlen (REPCHAR)); |
206 | 231 |
207 int fw = fm.width(REPCHAR[0]); | 232 _fixedFont = true; |
208 for(unsigned int i=1; i< strlen(REPCHAR); i++) | 233 |
209 { | 234 int fw = fm.width (REPCHAR[0]); |
210 if (fw != fm.width(REPCHAR[i])) | 235 for (unsigned int i = 1; i < strlen (REPCHAR); i++) |
211 { | 236 { |
212 _fixedFont = false; | 237 if (fw != fm.width (REPCHAR[i])) |
213 break; | 238 { |
214 } | 239 _fixedFont = false; |
215 } | 240 break; |
216 | 241 } |
217 if (_fontWidth < 1) | 242 } |
218 _fontWidth=1; | 243 |
219 | 244 if (_fontWidth < 1) |
220 _fontAscent = fm.ascent(); | 245 _fontWidth = 1; |
221 | 246 |
222 emit changedFontMetricSignal( _fontHeight, _fontWidth ); | 247 _fontAscent = fm.ascent (); |
223 propagateSize(); | 248 |
224 update(); | 249 emit changedFontMetricSignal (_fontHeight, _fontWidth); |
225 } | 250 propagateSize (); |
226 | 251 update (); |
227 void TerminalDisplay::setVTFont(const QFont& f) | 252 } |
228 { | 253 |
229 QFont font = f; | 254 void |
230 | 255 TerminalDisplay::setVTFont (const QFont & f) |
231 QFontMetrics metrics(font); | 256 { |
232 | 257 QFont font = f; |
233 if ( !QFontInfo(font).fixedPitch() ) | 258 |
234 { | 259 QFontMetrics metrics (font); |
235 //kWarning() << "Using an unsupported variable-width font in the terminal. This may produce display errors."; | 260 |
236 } | 261 if (!QFontInfo (font).fixedPitch ()) |
237 | 262 { |
238 if ( metrics.height() < height() && metrics.maxWidth() < width() ) | 263 //kWarning() << "Using an unsupported variable-width font in the terminal. This may produce display errors."; |
239 { | 264 } |
240 // hint that text should be drawn without anti-aliasing. | 265 |
241 // depending on the user's font configuration, this may not be respected | 266 if (metrics.height () < height () && metrics.maxWidth () < width ()) |
242 if (!_antialiasText) | 267 { |
243 font.setStyleStrategy( QFont::NoAntialias ); | 268 // hint that text should be drawn without anti-aliasing. |
244 | 269 // depending on the user's font configuration, this may not be respected |
245 // experimental optimization. Konsole assumes that the terminal is using a | 270 if (!_antialiasText) |
246 // mono-spaced font, in which case kerning information should have an effect. | 271 font.setStyleStrategy (QFont::NoAntialias); |
247 // Disabling kerning saves some computation when rendering text. | 272 |
248 font.setKerning(false); | 273 // experimental optimization. Konsole assumes that the terminal is using a |
249 | 274 // mono-spaced font, in which case kerning information should have an effect. |
250 QWidget::setFont(font); | 275 // Disabling kerning saves some computation when rendering text. |
251 fontChange(font); | 276 font.setKerning (false); |
252 } | 277 |
253 } | 278 QWidget::setFont (font); |
254 | 279 fontChange (font); |
255 void TerminalDisplay::setFont(const QFont &) | 280 } |
256 { | 281 } |
257 // ignore font change request if not coming from konsole itself | 282 |
283 void | |
284 TerminalDisplay::setFont (const QFont &) | |
285 { | |
286 // ignore font change request if not coming from konsole itself | |
258 } | 287 } |
259 | 288 |
260 /* ------------------------------------------------------------------------- */ | 289 /* ------------------------------------------------------------------------- */ |
261 /* */ | 290 /* */ |
262 /* Constructor / Destructor */ | 291 /* Constructor / Destructor */ |
263 /* */ | 292 /* */ |
264 /* ------------------------------------------------------------------------- */ | 293 /* ------------------------------------------------------------------------- */ |
265 | 294 |
266 TerminalDisplay::TerminalDisplay(QWidget *parent) | 295 TerminalDisplay::TerminalDisplay (QWidget * parent):QWidget (parent), _screenWindow (0), _allowBell (true), _gridLayout (0), |
267 :QWidget(parent) | 296 _fontHeight (1), _fontWidth (1), _fontAscent (1), _boldIntense (true), |
268 ,_screenWindow(0) | 297 _lines (1), _columns (1), _usedLines (1), _usedColumns (1), |
269 ,_allowBell(true) | 298 _contentHeight (1), _contentWidth (1), _image (0), _randomSeed (0), |
270 ,_gridLayout(0) | 299 _resizing (false), _terminalSizeHint (false), _terminalSizeStartup (true), |
271 ,_fontHeight(1) | 300 _bidiEnabled (false), _actSel (0), _wordSelectionMode (false), |
272 ,_fontWidth(1) | 301 _lineSelectionMode (false), _preserveLineBreaks (false), |
273 ,_fontAscent(1) | 302 _columnSelectionMode (false), _scrollbarLocation (NoScrollBar), |
274 ,_boldIntense(true) | 303 _wordCharacters (":@-./_~"), _bellMode (SystemBeepBell), _blinking (false), |
275 ,_lines(1) | 304 _hasBlinker (false), _cursorBlinking (false), _hasBlinkingCursor (false), |
276 ,_columns(1) | 305 _allowBlinkingText (true), _ctrlDrag (true), |
277 ,_usedLines(1) | 306 _tripleClickMode (SelectWholeLine), _isFixedSize (false), |
278 ,_usedColumns(1) | 307 _possibleTripleClick (false), _resizeWidget (0), _resizeTimer (0), |
279 ,_contentHeight(1) | 308 _flowControlWarningEnabled (false), _outputSuspendedLabel (0), |
280 ,_contentWidth(1) | 309 _lineSpacing (0), _colorsInverted (false), |
281 ,_image(0) | 310 _blendColor (qRgba (0, 0, 0, 0xff)), |
282 ,_randomSeed(0) | 311 _filterChain (new TerminalImageFilterChain ()), _cursorShape (BlockCursor) |
283 ,_resizing(false) | 312 { |
284 ,_terminalSizeHint(false) | 313 // terminal applications are not designed with Right-To-Left in mind, |
285 ,_terminalSizeStartup(true) | 314 // so the layout is forced to Left-To-Right |
286 ,_bidiEnabled(false) | 315 setLayoutDirection (Qt::LeftToRight); |
287 ,_actSel(0) | 316 |
288 ,_wordSelectionMode(false) | 317 // The offsets are not yet calculated. |
289 ,_lineSelectionMode(false) | 318 // Do not calculate these too often to be more smoothly when resizing |
290 ,_preserveLineBreaks(false) | 319 // konsole in opaque mode. |
291 ,_columnSelectionMode(false) | 320 _topMargin = DEFAULT_TOP_MARGIN; |
292 ,_scrollbarLocation(NoScrollBar) | 321 _leftMargin = DEFAULT_LEFT_MARGIN; |
293 ,_wordCharacters(":@-./_~") | 322 |
294 ,_bellMode(SystemBeepBell) | 323 // create scroll bar for scrolling output up and down |
295 ,_blinking(false) | 324 // set the scroll bar's slider to occupy the whole area of the scroll bar initially |
296 ,_hasBlinker(false) | 325 _scrollBar = new QScrollBar (this); |
297 ,_cursorBlinking(false) | 326 setScroll (0, 0); |
298 ,_hasBlinkingCursor(false) | 327 _scrollBar->setCursor (Qt::ArrowCursor); |
299 ,_allowBlinkingText(true) | 328 connect (_scrollBar, SIGNAL (valueChanged (int)), this, |
300 ,_ctrlDrag(true) | 329 SLOT (scrollBarPositionChanged (int))); |
301 ,_tripleClickMode(SelectWholeLine) | 330 |
302 ,_isFixedSize(false) | 331 // setup timers for blinking cursor and text |
303 ,_possibleTripleClick(false) | 332 _blinkTimer = new QTimer (this); |
304 ,_resizeWidget(0) | 333 connect (_blinkTimer, SIGNAL (timeout ()), this, SLOT (blinkEvent ())); |
305 ,_resizeTimer(0) | 334 _blinkCursorTimer = new QTimer (this); |
306 ,_flowControlWarningEnabled(false) | 335 connect (_blinkCursorTimer, SIGNAL (timeout ()), this, |
307 ,_outputSuspendedLabel(0) | 336 SLOT (blinkCursorEvent ())); |
308 ,_lineSpacing(0) | 337 |
309 ,_colorsInverted(false) | 338 //KCursor::setAutoHideCursor( this, true ); |
310 ,_blendColor(qRgba(0,0,0,0xff)) | 339 |
311 ,_filterChain(new TerminalImageFilterChain()) | 340 setUsesMouse (true); |
312 ,_cursorShape(BlockCursor) | 341 setColorTable (base_color_table); |
313 { | 342 setMouseTracking (true); |
314 // terminal applications are not designed with Right-To-Left in mind, | 343 |
315 // so the layout is forced to Left-To-Right | 344 // Enable drag and drop |
316 setLayoutDirection(Qt::LeftToRight); | 345 setAcceptDrops (true); // attempt |
317 | 346 dragInfo.state = diNone; |
318 // The offsets are not yet calculated. | 347 |
319 // Do not calculate these too often to be more smoothly when resizing | 348 setFocusPolicy (Qt::WheelFocus); |
320 // konsole in opaque mode. | 349 |
321 _topMargin = DEFAULT_TOP_MARGIN; | 350 // enable input method support |
322 _leftMargin = DEFAULT_LEFT_MARGIN; | 351 setAttribute (Qt::WA_InputMethodEnabled, true); |
323 | 352 |
324 // create scroll bar for scrolling output up and down | 353 // this is an important optimization, it tells Qt |
325 // set the scroll bar's slider to occupy the whole area of the scroll bar initially | 354 // that TerminalDisplay will handle repainting its entire area. |
326 _scrollBar = new QScrollBar(this); | 355 setAttribute (Qt::WA_OpaquePaintEvent); |
327 setScroll(0,0); | 356 |
328 _scrollBar->setCursor( Qt::ArrowCursor ); | 357 _gridLayout = new QGridLayout (this); |
329 connect(_scrollBar, SIGNAL(valueChanged(int)), this, | 358 _gridLayout->setContentsMargins (0, 0, 0, 0); |
330 SLOT(scrollBarPositionChanged(int))); | 359 |
331 | 360 setLayout (_gridLayout); |
332 // setup timers for blinking cursor and text | 361 |
333 _blinkTimer = new QTimer(this); | 362 new |
334 connect(_blinkTimer, SIGNAL(timeout()), this, SLOT(blinkEvent())); | 363 AutoScrollHandler (this); |
335 _blinkCursorTimer = new QTimer(this); | 364 } |
336 connect(_blinkCursorTimer, SIGNAL(timeout()), this, SLOT(blinkCursorEvent())); | 365 |
337 | 366 TerminalDisplay::~TerminalDisplay () |
338 //KCursor::setAutoHideCursor( this, true ); | 367 { |
339 | 368 disconnect (_blinkTimer); |
340 setUsesMouse(true); | 369 disconnect (_blinkCursorTimer); |
341 setColorTable(base_color_table); | 370 qApp->removeEventFilter (this); |
342 setMouseTracking(true); | 371 |
343 | 372 delete[]_image; |
344 // Enable drag and drop | 373 |
345 setAcceptDrops(true); // attempt | 374 delete _gridLayout; |
346 dragInfo.state = diNone; | 375 delete _outputSuspendedLabel; |
347 | 376 delete _filterChain; |
348 setFocusPolicy( Qt::WheelFocus ); | |
349 | |
350 // enable input method support | |
351 setAttribute(Qt::WA_InputMethodEnabled, true); | |
352 | |
353 // this is an important optimization, it tells Qt | |
354 // that TerminalDisplay will handle repainting its entire area. | |
355 setAttribute(Qt::WA_OpaquePaintEvent); | |
356 | |
357 _gridLayout = new QGridLayout(this); | |
358 _gridLayout->setContentsMargins(0, 0, 0, 0); | |
359 | |
360 setLayout( _gridLayout ); | |
361 | |
362 new AutoScrollHandler(this); | |
363 } | |
364 | |
365 TerminalDisplay::~TerminalDisplay() | |
366 { | |
367 disconnect(_blinkTimer); | |
368 disconnect(_blinkCursorTimer); | |
369 qApp->removeEventFilter( this ); | |
370 | |
371 delete[] _image; | |
372 | |
373 delete _gridLayout; | |
374 delete _outputSuspendedLabel; | |
375 delete _filterChain; | |
376 } | 377 } |
377 | 378 |
378 /* ------------------------------------------------------------------------- */ | 379 /* ------------------------------------------------------------------------- */ |
379 /* */ | 380 /* */ |
380 /* Display Operations */ | 381 /* Display Operations */ |
400 */ | 401 */ |
401 | 402 |
402 | 403 |
403 enum LineEncode | 404 enum LineEncode |
404 { | 405 { |
405 TopL = (1<<1), | 406 TopL = (1 << 1), |
406 TopC = (1<<2), | 407 TopC = (1 << 2), |
407 TopR = (1<<3), | 408 TopR = (1 << 3), |
408 | 409 |
409 LeftT = (1<<5), | 410 LeftT = (1 << 5), |
410 Int11 = (1<<6), | 411 Int11 = (1 << 6), |
411 Int12 = (1<<7), | 412 Int12 = (1 << 7), |
412 Int13 = (1<<8), | 413 Int13 = (1 << 8), |
413 RightT = (1<<9), | 414 RightT = (1 << 9), |
414 | 415 |
415 LeftC = (1<<10), | 416 LeftC = (1 << 10), |
416 Int21 = (1<<11), | 417 Int21 = (1 << 11), |
417 Int22 = (1<<12), | 418 Int22 = (1 << 12), |
418 Int23 = (1<<13), | 419 Int23 = (1 << 13), |
419 RightC = (1<<14), | 420 RightC = (1 << 14), |
420 | 421 |
421 LeftB = (1<<15), | 422 LeftB = (1 << 15), |
422 Int31 = (1<<16), | 423 Int31 = (1 << 16), |
423 Int32 = (1<<17), | 424 Int32 = (1 << 17), |
424 Int33 = (1<<18), | 425 Int33 = (1 << 18), |
425 RightB = (1<<19), | 426 RightB = (1 << 19), |
426 | 427 |
427 BotL = (1<<21), | 428 BotL = (1 << 21), |
428 BotC = (1<<22), | 429 BotC = (1 << 22), |
429 BotR = (1<<23) | 430 BotR = (1 << 23) |
430 }; | 431 }; |
431 | 432 |
432 #include "LineFont.h" | 433 #include "LineFont.h" |
433 | 434 |
434 static void drawLineChar(QPainter& paint, int x, int y, int w, int h, uchar code) | 435 static void |
435 { | 436 drawLineChar (QPainter & paint, int x, int y, int w, int h, uchar code) |
436 //Calculate cell midpoints, end points. | 437 { |
437 int cx = x + w/2; | 438 //Calculate cell midpoints, end points. |
438 int cy = y + h/2; | 439 int cx = x + w / 2; |
439 int ex = x + w - 1; | 440 int cy = y + h / 2; |
440 int ey = y + h - 1; | 441 int ex = x + w - 1; |
441 | 442 int ey = y + h - 1; |
442 quint32 toDraw = LineChars[code]; | 443 |
443 | 444 quint32 toDraw = LineChars[code]; |
444 //Top _lines: | 445 |
445 if (toDraw & TopL) | 446 //Top _lines: |
446 paint.drawLine(cx-1, y, cx-1, cy-2); | 447 if (toDraw & TopL) |
447 if (toDraw & TopC) | 448 paint.drawLine (cx - 1, y, cx - 1, cy - 2); |
448 paint.drawLine(cx, y, cx, cy-2); | 449 if (toDraw & TopC) |
449 if (toDraw & TopR) | 450 paint.drawLine (cx, y, cx, cy - 2); |
450 paint.drawLine(cx+1, y, cx+1, cy-2); | 451 if (toDraw & TopR) |
451 | 452 paint.drawLine (cx + 1, y, cx + 1, cy - 2); |
452 //Bot _lines: | 453 |
453 if (toDraw & BotL) | 454 //Bot _lines: |
454 paint.drawLine(cx-1, cy+2, cx-1, ey); | 455 if (toDraw & BotL) |
455 if (toDraw & BotC) | 456 paint.drawLine (cx - 1, cy + 2, cx - 1, ey); |
456 paint.drawLine(cx, cy+2, cx, ey); | 457 if (toDraw & BotC) |
457 if (toDraw & BotR) | 458 paint.drawLine (cx, cy + 2, cx, ey); |
458 paint.drawLine(cx+1, cy+2, cx+1, ey); | 459 if (toDraw & BotR) |
459 | 460 paint.drawLine (cx + 1, cy + 2, cx + 1, ey); |
460 //Left _lines: | 461 |
461 if (toDraw & LeftT) | 462 //Left _lines: |
462 paint.drawLine(x, cy-1, cx-2, cy-1); | 463 if (toDraw & LeftT) |
463 if (toDraw & LeftC) | 464 paint.drawLine (x, cy - 1, cx - 2, cy - 1); |
464 paint.drawLine(x, cy, cx-2, cy); | 465 if (toDraw & LeftC) |
465 if (toDraw & LeftB) | 466 paint.drawLine (x, cy, cx - 2, cy); |
466 paint.drawLine(x, cy+1, cx-2, cy+1); | 467 if (toDraw & LeftB) |
467 | 468 paint.drawLine (x, cy + 1, cx - 2, cy + 1); |
468 //Right _lines: | 469 |
469 if (toDraw & RightT) | 470 //Right _lines: |
470 paint.drawLine(cx+2, cy-1, ex, cy-1); | 471 if (toDraw & RightT) |
471 if (toDraw & RightC) | 472 paint.drawLine (cx + 2, cy - 1, ex, cy - 1); |
472 paint.drawLine(cx+2, cy, ex, cy); | 473 if (toDraw & RightC) |
473 if (toDraw & RightB) | 474 paint.drawLine (cx + 2, cy, ex, cy); |
474 paint.drawLine(cx+2, cy+1, ex, cy+1); | 475 if (toDraw & RightB) |
475 | 476 paint.drawLine (cx + 2, cy + 1, ex, cy + 1); |
476 //Intersection points. | 477 |
477 if (toDraw & Int11) | 478 //Intersection points. |
478 paint.drawPoint(cx-1, cy-1); | 479 if (toDraw & Int11) |
479 if (toDraw & Int12) | 480 paint.drawPoint (cx - 1, cy - 1); |
480 paint.drawPoint(cx, cy-1); | 481 if (toDraw & Int12) |
481 if (toDraw & Int13) | 482 paint.drawPoint (cx, cy - 1); |
482 paint.drawPoint(cx+1, cy-1); | 483 if (toDraw & Int13) |
483 | 484 paint.drawPoint (cx + 1, cy - 1); |
484 if (toDraw & Int21) | 485 |
485 paint.drawPoint(cx-1, cy); | 486 if (toDraw & Int21) |
486 if (toDraw & Int22) | 487 paint.drawPoint (cx - 1, cy); |
487 paint.drawPoint(cx, cy); | 488 if (toDraw & Int22) |
488 if (toDraw & Int23) | 489 paint.drawPoint (cx, cy); |
489 paint.drawPoint(cx+1, cy); | 490 if (toDraw & Int23) |
490 | 491 paint.drawPoint (cx + 1, cy); |
491 if (toDraw & Int31) | 492 |
492 paint.drawPoint(cx-1, cy+1); | 493 if (toDraw & Int31) |
493 if (toDraw & Int32) | 494 paint.drawPoint (cx - 1, cy + 1); |
494 paint.drawPoint(cx, cy+1); | 495 if (toDraw & Int32) |
495 if (toDraw & Int33) | 496 paint.drawPoint (cx, cy + 1); |
496 paint.drawPoint(cx+1, cy+1); | 497 if (toDraw & Int33) |
497 | 498 paint.drawPoint (cx + 1, cy + 1); |
498 } | 499 |
499 | 500 } |
500 void TerminalDisplay::drawLineCharString( QPainter& painter, int x, int y, const QString& str, | 501 |
501 const Character* attributes) | 502 void |
502 { | 503 TerminalDisplay::drawLineCharString (QPainter & painter, int x, int y, |
503 const QPen& currentPen = painter.pen(); | 504 const QString & str, |
504 | 505 const Character * attributes) |
505 if ( (attributes->rendition & RE_BOLD) && _boldIntense ) | 506 { |
506 { | 507 const QPen & currentPen = painter.pen (); |
507 QPen boldPen(currentPen); | 508 |
508 boldPen.setWidth(3); | 509 if ((attributes->rendition & RE_BOLD) && _boldIntense) |
509 painter.setPen( boldPen ); | 510 { |
510 } | 511 QPen boldPen (currentPen); |
511 | 512 boldPen.setWidth (3); |
512 for (int i=0 ; i < str.length(); i++) | 513 painter.setPen (boldPen); |
513 { | 514 } |
514 uchar code = str[i].cell(); | 515 |
515 if (LineChars[code]) | 516 for (int i = 0; i < str.length (); i++) |
516 drawLineChar(painter, x + (_fontWidth*i), y, _fontWidth, _fontHeight, code); | 517 { |
517 } | 518 uchar code = str[i].cell (); |
518 | 519 if (LineChars[code]) |
519 painter.setPen( currentPen ); | 520 drawLineChar (painter, x + (_fontWidth * i), y, _fontWidth, |
520 } | 521 _fontHeight, code); |
521 | 522 } |
522 void TerminalDisplay::setKeyboardCursorShape(KeyboardCursorShape shape) | 523 |
523 { | 524 painter.setPen (currentPen); |
524 _cursorShape = shape; | 525 } |
525 } | 526 |
526 TerminalDisplay::KeyboardCursorShape TerminalDisplay::keyboardCursorShape() const | 527 void |
527 { | 528 TerminalDisplay::setKeyboardCursorShape (KeyboardCursorShape shape) |
528 return _cursorShape; | 529 { |
529 } | 530 _cursorShape = shape; |
530 void TerminalDisplay::setKeyboardCursorColor(bool useForegroundColor, const QColor& color) | 531 } |
531 { | 532 |
532 if (useForegroundColor) | 533 TerminalDisplay::KeyboardCursorShape TerminalDisplay::keyboardCursorShape () const |
533 _cursorColor = QColor(); // an invalid color means that | 534 { |
534 // the foreground color of the | 535 return _cursorShape; |
535 // current character should | 536 } |
536 // be used | 537 |
537 | 538 void |
538 else | 539 TerminalDisplay::setKeyboardCursorColor (bool useForegroundColor, |
539 _cursorColor = color; | 540 const QColor & color) |
540 } | 541 { |
541 QColor TerminalDisplay::keyboardCursorColor() const | 542 if (useForegroundColor) |
542 { | 543 _cursorColor = QColor (); // an invalid color means that |
543 return _cursorColor; | 544 // the foreground color of the |
544 } | 545 // current character should |
545 | 546 // be used |
546 void TerminalDisplay::setOpacity(qreal opacity) | 547 |
547 { | 548 else |
548 QColor color(_blendColor); | 549 _cursorColor = color; |
549 color.setAlphaF(opacity); | 550 } |
550 | 551 |
551 // enable automatic background filling to prevent the display | 552 QColor |
552 // flickering if there is no transparency | 553 TerminalDisplay::keyboardCursorColor () const |
553 /*if ( color.alpha() == 255 ) | 554 { |
554 { | 555 return _cursorColor; |
555 setAutoFillBackground(true); | 556 } |
556 } | 557 |
557 else | 558 void |
558 { | 559 TerminalDisplay::setOpacity (qreal opacity) |
559 setAutoFillBackground(false); | 560 { |
560 }*/ | 561 QColor color (_blendColor); |
561 | 562 color.setAlphaF (opacity); |
562 _blendColor = color.rgba(); | 563 |
563 } | 564 // enable automatic background filling to prevent the display |
564 | 565 // flickering if there is no transparency |
565 void TerminalDisplay::drawBackground(QPainter& painter, const QRect& rect, const QColor& backgroundColor, bool useOpacitySetting ) | 566 /*if ( color.alpha() == 255 ) |
566 { | 567 { |
567 // the area of the widget showing the contents of the terminal display is drawn | 568 setAutoFillBackground(true); |
568 // using the background color from the color scheme set with setColorTable() | 569 } |
569 // | 570 else |
570 // the area of the widget behind the scroll-bar is drawn using the background | 571 { |
571 // brush from the scroll-bar's palette, to give the effect of the scroll-bar | 572 setAutoFillBackground(false); |
572 // being outside of the terminal display and visual consistency with other KDE | 573 } */ |
573 // applications. | 574 |
574 // | 575 _blendColor = color.rgba (); |
575 QRect scrollBarArea = _scrollBar->isVisible() ? | 576 } |
576 rect.intersected(_scrollBar->geometry()) : | 577 |
577 QRect(); | 578 void |
578 QRegion contentsRegion = QRegion(rect).subtracted(scrollBarArea); | 579 TerminalDisplay::drawBackground (QPainter & painter, const QRect & rect, |
579 QRect contentsRect = contentsRegion.boundingRect(); | 580 const QColor & backgroundColor, |
580 | 581 bool useOpacitySetting) |
581 if ( HAVE_TRANSPARENCY && qAlpha(_blendColor) < 0xff && useOpacitySetting ) | 582 { |
582 { | 583 // the area of the widget showing the contents of the terminal display is drawn |
583 QColor color(backgroundColor); | 584 // using the background color from the color scheme set with setColorTable() |
584 color.setAlpha(qAlpha(_blendColor)); | 585 // |
585 | 586 // the area of the widget behind the scroll-bar is drawn using the background |
586 painter.save(); | 587 // brush from the scroll-bar's palette, to give the effect of the scroll-bar |
587 painter.setCompositionMode(QPainter::CompositionMode_Source); | 588 // being outside of the terminal display and visual consistency with other KDE |
588 painter.fillRect(contentsRect, color); | 589 // applications. |
589 painter.restore(); | 590 // |
590 } | 591 QRect scrollBarArea = _scrollBar->isVisible ()? |
591 else | 592 rect.intersected (_scrollBar->geometry ()) : QRect (); |
592 painter.fillRect(contentsRect, backgroundColor); | 593 QRegion contentsRegion = QRegion (rect).subtracted (scrollBarArea); |
593 | 594 QRect contentsRect = contentsRegion.boundingRect (); |
594 painter.fillRect(scrollBarArea,_scrollBar->palette().background()); | 595 |
595 } | 596 if (HAVE_TRANSPARENCY && qAlpha (_blendColor) < 0xff && useOpacitySetting) |
596 | 597 { |
597 void TerminalDisplay::drawCursor(QPainter& painter, | 598 QColor color (backgroundColor); |
598 const QRect& rect, | 599 color.setAlpha (qAlpha (_blendColor)); |
599 const QColor& foregroundColor, | 600 |
600 const QColor& /*backgroundColor*/, | 601 painter.save (); |
601 bool& invertCharacterColor) | 602 painter.setCompositionMode (QPainter::CompositionMode_Source); |
602 { | 603 painter.fillRect (contentsRect, color); |
603 QRect cursorRect = rect; | 604 painter.restore (); |
604 cursorRect.setHeight(_fontHeight - _lineSpacing - 1); | 605 } |
605 | 606 else |
606 if (!_cursorBlinking) | 607 painter.fillRect (contentsRect, backgroundColor); |
607 { | 608 |
608 if ( _cursorColor.isValid() ) | 609 painter.fillRect (scrollBarArea, _scrollBar->palette ().background ()); |
609 painter.setPen(_cursorColor); | 610 } |
610 else | 611 |
611 painter.setPen(foregroundColor); | 612 void |
612 | 613 TerminalDisplay::drawCursor (QPainter & painter, |
613 if ( _cursorShape == BlockCursor ) | 614 const QRect & rect, |
614 { | 615 const QColor & foregroundColor, |
615 // draw the cursor outline, adjusting the area so that | 616 const QColor & /*backgroundColor */ , |
616 // it is draw entirely inside 'rect' | 617 bool & invertCharacterColor) |
617 int penWidth = qMax(1,painter.pen().width()); | 618 { |
618 | 619 QRect cursorRect = rect; |
619 painter.drawRect(cursorRect.adjusted(penWidth/2, | 620 cursorRect.setHeight (_fontHeight - _lineSpacing - 1); |
620 penWidth/2, | 621 |
621 - penWidth/2 - penWidth%2, | 622 if (!_cursorBlinking) |
622 - penWidth/2 - penWidth%2)); | 623 { |
623 if ( hasFocus() ) | 624 if (_cursorColor.isValid ()) |
624 { | 625 painter.setPen (_cursorColor); |
625 painter.fillRect(cursorRect, _cursorColor.isValid() ? _cursorColor : foregroundColor); | 626 else |
626 | 627 painter.setPen (foregroundColor); |
627 if ( !_cursorColor.isValid() ) | 628 |
628 { | 629 if (_cursorShape == BlockCursor) |
629 // invert the colour used to draw the text to ensure that the character at | 630 { |
630 // the cursor position is readable | 631 // draw the cursor outline, adjusting the area so that |
631 invertCharacterColor = true; | 632 // it is draw entirely inside 'rect' |
632 } | 633 int penWidth = qMax (1, painter.pen ().width ()); |
633 } | 634 |
634 } | 635 painter.drawRect (cursorRect.adjusted (penWidth / 2, |
635 else if ( _cursorShape == UnderlineCursor ) | 636 penWidth / 2, |
636 painter.drawLine(cursorRect.left(), | 637 -penWidth / 2 - penWidth % 2, |
637 cursorRect.bottom(), | 638 -penWidth / 2 - |
638 cursorRect.right(), | 639 penWidth % 2)); |
639 cursorRect.bottom()); | 640 if (hasFocus ()) |
640 else if ( _cursorShape == IBeamCursor ) | 641 { |
641 painter.drawLine(cursorRect.left(), | 642 painter.fillRect (cursorRect, |
642 cursorRect.top(), | 643 _cursorColor. |
643 cursorRect.left(), | 644 isValid ()? _cursorColor : foregroundColor); |
644 cursorRect.bottom()); | 645 |
645 | 646 if (!_cursorColor.isValid ()) |
646 } | 647 { |
647 } | 648 // invert the colour used to draw the text to ensure that the character at |
648 | 649 // the cursor position is readable |
649 void TerminalDisplay::drawCharacters(QPainter& painter, | 650 invertCharacterColor = true; |
650 const QRect& rect, | 651 } |
651 const QString& text, | 652 } |
652 const Character* style, | 653 } |
653 bool invertCharacterColor) | 654 else if (_cursorShape == UnderlineCursor) |
654 { | 655 painter.drawLine (cursorRect.left (), |
655 // don't draw text which is currently blinking | 656 cursorRect.bottom (), |
656 if ( _blinking && (style->rendition & RE_BLINK) ) | 657 cursorRect.right (), cursorRect.bottom ()); |
657 return; | 658 else if (_cursorShape == IBeamCursor) |
658 | 659 painter.drawLine (cursorRect.left (), |
659 // setup bold and underline | 660 cursorRect.top (), |
660 bool useBold; | 661 cursorRect.left (), cursorRect.bottom ()); |
661 ColorEntry::FontWeight weight = style->fontWeight(_colorTable); | 662 |
662 if (weight == ColorEntry::UseCurrentFormat) | 663 } |
663 useBold = ((style->rendition & RE_BOLD) && _boldIntense) || font().bold(); | 664 } |
664 else | 665 |
665 useBold = (weight == ColorEntry::Bold) ? true : false; | 666 void |
666 bool useUnderline = style->rendition & RE_UNDERLINE || font().underline(); | 667 TerminalDisplay::drawCharacters (QPainter & painter, |
667 | 668 const QRect & rect, |
668 QFont font = painter.font(); | 669 const QString & text, |
669 if ( font.bold() != useBold | 670 const Character * style, |
670 || font.underline() != useUnderline ) | 671 bool invertCharacterColor) |
671 { | 672 { |
672 font.setBold(useBold); | 673 // don't draw text which is currently blinking |
673 font.setUnderline(useUnderline); | 674 if (_blinking && (style->rendition & RE_BLINK)) |
674 painter.setFont(font); | 675 return; |
675 } | 676 |
676 | 677 // setup bold and underline |
677 // setup pen | 678 bool useBold; |
678 const CharacterColor& textColor = ( invertCharacterColor ? style->backgroundColor : style->foregroundColor ); | 679 ColorEntry::FontWeight weight = style->fontWeight (_colorTable); |
679 const QColor color = textColor.color(_colorTable); | 680 if (weight == ColorEntry::UseCurrentFormat) |
680 QPen pen = painter.pen(); | 681 useBold = ((style->rendition & RE_BOLD) && _boldIntense) |
681 if ( pen.color() != color ) | 682 || font ().bold (); |
682 { | 683 else |
683 pen.setColor(color); | 684 useBold = (weight == ColorEntry::Bold) ? true : false; |
684 painter.setPen(color); | 685 bool useUnderline = style->rendition & RE_UNDERLINE || font ().underline (); |
685 } | 686 |
686 | 687 QFont font = painter.font (); |
687 // draw text | 688 if (font.bold () != useBold || font.underline () != useUnderline) |
688 if ( isLineCharString(text) ) | 689 { |
689 drawLineCharString(painter,rect.x(),rect.y(),text,style); | 690 font.setBold (useBold); |
690 else | 691 font.setUnderline (useUnderline); |
691 { | 692 painter.setFont (font); |
692 // the drawText(rect,flags,string) overload is used here with null flags | 693 } |
693 // instead of drawText(rect,string) because the (rect,string) overload causes | 694 |
694 // the application's default layout direction to be used instead of | 695 // setup pen |
695 // the widget-specific layout direction, which should always be | 696 const CharacterColor & textColor = |
696 // Qt::LeftToRight for this widget | 697 (invertCharacterColor ? style->backgroundColor : style->foregroundColor); |
697 // This was discussed in: http://lists.kde.org/?t=120552223600002&r=1&w=2 | 698 const QColor color = textColor.color (_colorTable); |
698 if (_bidiEnabled) | 699 QPen pen = painter.pen (); |
699 painter.drawText(rect,0,text); | 700 if (pen.color () != color) |
700 else | 701 { |
701 painter.drawText(rect,0,LTR_OVERRIDE_CHAR+text); | 702 pen.setColor (color); |
702 } | 703 painter.setPen (color); |
703 } | 704 } |
704 | 705 |
705 void TerminalDisplay::drawTextFragment(QPainter& painter , | 706 // draw text |
706 const QRect& rect, | 707 if (isLineCharString (text)) |
707 const QString& text, | 708 drawLineCharString (painter, rect.x (), rect.y (), text, style); |
708 const Character* style) | 709 else |
709 { | 710 { |
710 painter.save(); | 711 // the drawText(rect,flags,string) overload is used here with null flags |
711 | 712 // instead of drawText(rect,string) because the (rect,string) overload causes |
712 // setup painter | 713 // the application's default layout direction to be used instead of |
713 const QColor foregroundColor = style->foregroundColor.color(_colorTable); | 714 // the widget-specific layout direction, which should always be |
714 const QColor backgroundColor = style->backgroundColor.color(_colorTable); | 715 // Qt::LeftToRight for this widget |
715 | 716 // This was discussed in: http://lists.kde.org/?t=120552223600002&r=1&w=2 |
716 // draw background if different from the display's background color | 717 if (_bidiEnabled) |
717 if ( backgroundColor != palette().background().color() ) | 718 painter.drawText (rect, 0, text); |
718 drawBackground(painter,rect,backgroundColor, | 719 else |
719 false /* do not use transparency */); | 720 painter.drawText (rect, 0, LTR_OVERRIDE_CHAR + text); |
720 | 721 } |
721 // draw cursor shape if the current character is the cursor | 722 } |
722 // this may alter the foreground and background colors | 723 |
723 bool invertCharacterColor = false; | 724 void |
724 if ( style->rendition & RE_CURSOR ) | 725 TerminalDisplay::drawTextFragment (QPainter & painter, |
725 drawCursor(painter,rect,foregroundColor,backgroundColor,invertCharacterColor); | 726 const QRect & rect, |
726 | 727 const QString & text, |
727 // draw text | 728 const Character * style) |
728 drawCharacters(painter,rect,text,style,invertCharacterColor); | 729 { |
729 | 730 painter.save (); |
730 painter.restore(); | 731 |
731 } | 732 // setup painter |
732 | 733 const QColor foregroundColor = style->foregroundColor.color (_colorTable); |
733 void TerminalDisplay::setRandomSeed(uint randomSeed) { _randomSeed = randomSeed; } | 734 const QColor backgroundColor = style->backgroundColor.color (_colorTable); |
734 uint TerminalDisplay::randomSeed() const { return _randomSeed; } | 735 |
736 // draw background if different from the display's background color | |
737 if (backgroundColor != palette ().background ().color ()) | |
738 drawBackground (painter, rect, backgroundColor, | |
739 false /* do not use transparency */ ); | |
740 | |
741 // draw cursor shape if the current character is the cursor | |
742 // this may alter the foreground and background colors | |
743 bool invertCharacterColor = false; | |
744 if (style->rendition & RE_CURSOR) | |
745 drawCursor (painter, rect, foregroundColor, backgroundColor, | |
746 invertCharacterColor); | |
747 | |
748 // draw text | |
749 drawCharacters (painter, rect, text, style, invertCharacterColor); | |
750 | |
751 painter.restore (); | |
752 } | |
753 | |
754 void | |
755 TerminalDisplay::setRandomSeed (uint randomSeed) | |
756 { | |
757 _randomSeed = randomSeed; | |
758 } | |
759 | |
760 uint | |
761 TerminalDisplay::randomSeed () const | |
762 { | |
763 return _randomSeed; | |
764 } | |
735 | 765 |
736 #if 0 | 766 #if 0 |
737 /*! | 767 /*! |
738 Set XIM Position | 768 Set XIM Position |
739 */ | 769 */ |
740 void TerminalDisplay::setCursorPos(const int curx, const int cury) | 770 void |
741 { | 771 TerminalDisplay::setCursorPos (const int curx, const int cury) |
742 QPoint tL = contentsRect().topLeft(); | 772 { |
743 int tLx = tL.x(); | 773 QPoint tL = contentsRect ().topLeft (); |
744 int tLy = tL.y(); | 774 int tLx = tL.x (); |
745 | 775 int tLy = tL.y (); |
746 int xpos, ypos; | 776 |
747 ypos = _topMargin + tLy + _fontHeight*(cury-1) + _fontAscent; | 777 int xpos, ypos; |
748 xpos = _leftMargin + tLx + _fontWidth*curx; | 778 ypos = _topMargin + tLy + _fontHeight * (cury - 1) + _fontAscent; |
749 _cursorLine = cury; | 779 xpos = _leftMargin + tLx + _fontWidth * curx; |
750 _cursorCol = curx; | 780 _cursorLine = cury; |
781 _cursorCol = curx; | |
751 } | 782 } |
752 #endif | 783 #endif |
753 | 784 |
754 // scrolls the image by 'lines', down if lines > 0 or up otherwise. | 785 // scrolls the image by 'lines', down if lines > 0 or up otherwise. |
755 // | 786 // |
757 // image as it receives input, and when the view is updated, it calls scrollImage() | 788 // image as it receives input, and when the view is updated, it calls scrollImage() |
758 // with the final scroll amount. this improves performance because scrolling the | 789 // with the final scroll amount. this improves performance because scrolling the |
759 // display is much cheaper than re-rendering all the text for the | 790 // display is much cheaper than re-rendering all the text for the |
760 // part of the image which has moved up or down. | 791 // part of the image which has moved up or down. |
761 // Instead only new lines have to be drawn | 792 // Instead only new lines have to be drawn |
762 void TerminalDisplay::scrollImage(int lines , const QRect& screenWindowRegion) | 793 void |
763 { | 794 TerminalDisplay::scrollImage (int lines, const QRect & screenWindowRegion) |
764 // if the flow control warning is enabled this will interfere with the | 795 { |
765 // scrolling optimizations and cause artifacts. the simple solution here | 796 // if the flow control warning is enabled this will interfere with the |
766 // is to just disable the optimization whilst it is visible | 797 // scrolling optimizations and cause artifacts. the simple solution here |
767 if ( _outputSuspendedLabel && _outputSuspendedLabel->isVisible() ) | 798 // is to just disable the optimization whilst it is visible |
768 return; | 799 if (_outputSuspendedLabel && _outputSuspendedLabel->isVisible ()) |
769 | 800 return; |
770 // constrain the region to the display | 801 |
771 // the bottom of the region is capped to the number of lines in the display's | 802 // constrain the region to the display |
772 // internal image - 2, so that the height of 'region' is strictly less | 803 // the bottom of the region is capped to the number of lines in the display's |
773 // than the height of the internal image. | 804 // internal image - 2, so that the height of 'region' is strictly less |
774 QRect region = screenWindowRegion; | 805 // than the height of the internal image. |
775 region.setBottom( qMin(region.bottom(),this->_lines-2) ); | 806 QRect region = screenWindowRegion; |
776 | 807 region.setBottom (qMin (region.bottom (), this->_lines - 2)); |
777 // return if there is nothing to do | 808 |
778 if ( lines == 0 | 809 // return if there is nothing to do |
779 || _image == 0 | 810 if (lines == 0 |
780 || !region.isValid() | 811 || _image == 0 |
781 || (region.top() + abs(lines)) >= region.bottom() | 812 || !region.isValid () |
782 || this->_lines <= region.height() ) return; | 813 || (region.top () + abs (lines)) >= region.bottom () |
783 | 814 || this->_lines <= region.height ()) |
784 // hide terminal size label to prevent it being scrolled | 815 return; |
785 if (_resizeWidget && _resizeWidget->isVisible()) | 816 |
786 _resizeWidget->hide(); | 817 // hide terminal size label to prevent it being scrolled |
787 | 818 if (_resizeWidget && _resizeWidget->isVisible ()) |
788 // Note: With Qt 4.4 the left edge of the scrolled area must be at 0 | 819 _resizeWidget->hide (); |
789 // to get the correct (newly exposed) part of the widget repainted. | 820 |
790 // | 821 // Note: With Qt 4.4 the left edge of the scrolled area must be at 0 |
791 // The right edge must be before the left edge of the scroll bar to | 822 // to get the correct (newly exposed) part of the widget repainted. |
792 // avoid triggering a repaint of the entire widget, the distance is | 823 // |
793 // given by SCROLLBAR_CONTENT_GAP | 824 // The right edge must be before the left edge of the scroll bar to |
794 // | 825 // avoid triggering a repaint of the entire widget, the distance is |
795 // Set the QT_FLUSH_PAINT environment variable to '1' before starting the | 826 // given by SCROLLBAR_CONTENT_GAP |
796 // application to monitor repainting. | 827 // |
797 // | 828 // Set the QT_FLUSH_PAINT environment variable to '1' before starting the |
798 int scrollBarWidth = _scrollBar->isHidden() ? 0 : _scrollBar->width(); | 829 // application to monitor repainting. |
799 const int SCROLLBAR_CONTENT_GAP = 1; | 830 // |
800 QRect scrollRect; | 831 int scrollBarWidth = _scrollBar->isHidden ()? 0 : _scrollBar->width (); |
801 if ( _scrollbarLocation == ScrollBarLeft ) | 832 const int SCROLLBAR_CONTENT_GAP = 1; |
802 { | 833 QRect scrollRect; |
803 scrollRect.setLeft(scrollBarWidth+SCROLLBAR_CONTENT_GAP); | 834 if (_scrollbarLocation == ScrollBarLeft) |
804 scrollRect.setRight(width()); | 835 { |
805 } | 836 scrollRect.setLeft (scrollBarWidth + SCROLLBAR_CONTENT_GAP); |
837 scrollRect.setRight (width ()); | |
838 } | |
839 else | |
840 { | |
841 scrollRect.setLeft (0); | |
842 scrollRect.setRight (width () - scrollBarWidth - SCROLLBAR_CONTENT_GAP); | |
843 } | |
844 void *firstCharPos = &_image[region.top () * this->_columns]; | |
845 void *lastCharPos = &_image[(region.top () + abs (lines)) * this->_columns]; | |
846 | |
847 int top = _topMargin + (region.top () * _fontHeight); | |
848 int linesToMove = region.height () - abs (lines); | |
849 int bytesToMove = linesToMove * this->_columns * sizeof (Character); | |
850 | |
851 Q_ASSERT (linesToMove > 0); | |
852 Q_ASSERT (bytesToMove > 0); | |
853 | |
854 //scroll internal image | |
855 if (lines > 0) | |
856 { | |
857 // check that the memory areas that we are going to move are valid | |
858 Q_ASSERT ((char *) lastCharPos + bytesToMove < | |
859 (char *) (_image + (this->_lines * this->_columns))); | |
860 | |
861 Q_ASSERT ((lines * this->_columns) < _imageSize); | |
862 | |
863 //scroll internal image down | |
864 memmove (firstCharPos, lastCharPos, bytesToMove); | |
865 | |
866 //set region of display to scroll | |
867 scrollRect.setTop (top); | |
868 } | |
869 else | |
870 { | |
871 // check that the memory areas that we are going to move are valid | |
872 Q_ASSERT ((char *) firstCharPos + bytesToMove < | |
873 (char *) (_image + (this->_lines * this->_columns))); | |
874 | |
875 //scroll internal image up | |
876 memmove (lastCharPos, firstCharPos, bytesToMove); | |
877 | |
878 //set region of the display to scroll | |
879 scrollRect.setTop (top + abs (lines) * _fontHeight); | |
880 } | |
881 scrollRect.setHeight (linesToMove * _fontHeight); | |
882 | |
883 Q_ASSERT (scrollRect.isValid () && !scrollRect.isEmpty ()); | |
884 | |
885 //scroll the display vertically to match internal _image | |
886 scroll (0, _fontHeight * (-lines), scrollRect); | |
887 } | |
888 | |
889 QRegion | |
890 TerminalDisplay::hotSpotRegion () const | |
891 { | |
892 QRegion region; | |
893 foreach (Filter::HotSpot * hotSpot, _filterChain->hotSpots ()) | |
894 { | |
895 QRect r; | |
896 if (hotSpot->startLine () == hotSpot->endLine ()) | |
897 { | |
898 r.setLeft (hotSpot->startColumn ()); | |
899 r.setTop (hotSpot->startLine ()); | |
900 r.setRight (hotSpot->endColumn ()); | |
901 r.setBottom (hotSpot->endLine ()); | |
902 region |= imageToWidget (r);; | |
903 } | |
806 else | 904 else |
807 { | 905 { |
808 scrollRect.setLeft(0); | 906 r.setLeft (hotSpot->startColumn ()); |
809 scrollRect.setRight(width() - scrollBarWidth - SCROLLBAR_CONTENT_GAP); | 907 r.setTop (hotSpot->startLine ()); |
810 } | 908 r.setRight (_columns); |
811 void* firstCharPos = &_image[ region.top() * this->_columns ]; | 909 r.setBottom (hotSpot->startLine ()); |
812 void* lastCharPos = &_image[ (region.top() + abs(lines)) * this->_columns ]; | 910 region |= imageToWidget (r);; |
813 | 911 for (int line = hotSpot->startLine () + 1; line < hotSpot->endLine (); |
814 int top = _topMargin + (region.top() * _fontHeight); | 912 line++) |
815 int linesToMove = region.height() - abs(lines); | 913 { |
816 int bytesToMove = linesToMove * | 914 r.setLeft (0); |
817 this->_columns * | 915 r.setTop (line); |
818 sizeof(Character); | 916 r.setRight (_columns); |
819 | 917 r.setBottom (line); |
820 Q_ASSERT( linesToMove > 0 ); | 918 region |= imageToWidget (r);; |
821 Q_ASSERT( bytesToMove > 0 ); | 919 } |
822 | 920 r.setLeft (0); |
823 //scroll internal image | 921 r.setTop (hotSpot->endLine ()); |
824 if ( lines > 0 ) | 922 r.setRight (hotSpot->endColumn ()); |
825 { | 923 r.setBottom (hotSpot->endLine ()); |
826 // check that the memory areas that we are going to move are valid | 924 region |= imageToWidget (r);; |
827 Q_ASSERT( (char*)lastCharPos + bytesToMove < | 925 } |
828 (char*)(_image + (this->_lines * this->_columns)) ); | 926 } |
829 | 927 return region; |
830 Q_ASSERT( (lines*this->_columns) < _imageSize ); | 928 } |
831 | 929 |
832 //scroll internal image down | 930 void |
833 memmove( firstCharPos , lastCharPos , bytesToMove ); | 931 TerminalDisplay::processFilters () |
834 | 932 { |
835 //set region of display to scroll | 933 if (!_screenWindow) |
836 scrollRect.setTop(top); | 934 return; |
837 } | 935 |
838 else | 936 QRegion preUpdateHotSpots = hotSpotRegion (); |
839 { | 937 |
840 // check that the memory areas that we are going to move are valid | 938 // use _screenWindow->getImage() here rather than _image because |
841 Q_ASSERT( (char*)firstCharPos + bytesToMove < | 939 // other classes may call processFilters() when this display's |
842 (char*)(_image + (this->_lines * this->_columns)) ); | 940 // ScreenWindow emits a scrolled() signal - which will happen before |
843 | 941 // updateImage() is called on the display and therefore _image is |
844 //scroll internal image up | 942 // out of date at this point |
845 memmove( lastCharPos , firstCharPos , bytesToMove ); | 943 _filterChain->setImage (_screenWindow->getImage (), |
846 | 944 _screenWindow->windowLines (), |
847 //set region of the display to scroll | 945 _screenWindow->windowColumns (), |
848 scrollRect.setTop(top + abs(lines) * _fontHeight); | 946 _screenWindow->getLineProperties ()); |
849 } | 947 _filterChain->process (); |
850 scrollRect.setHeight(linesToMove * _fontHeight ); | 948 |
851 | 949 QRegion postUpdateHotSpots = hotSpotRegion (); |
852 Q_ASSERT(scrollRect.isValid() && !scrollRect.isEmpty()); | 950 |
853 | 951 update (preUpdateHotSpots | postUpdateHotSpots); |
854 //scroll the display vertically to match internal _image | 952 } |
855 scroll( 0 , _fontHeight * (-lines) , scrollRect ); | 953 |
856 } | 954 void |
857 | 955 TerminalDisplay::updateImage () |
858 QRegion TerminalDisplay::hotSpotRegion() const | 956 { |
859 { | 957 if (!_screenWindow) |
860 QRegion region; | 958 return; |
861 foreach( Filter::HotSpot* hotSpot , _filterChain->hotSpots() ) | 959 |
862 { | 960 // optimization - scroll the existing image where possible and |
863 QRect r; | 961 // avoid expensive text drawing for parts of the image that |
864 if (hotSpot->startLine()==hotSpot->endLine()) { | 962 // can simply be moved up or down |
865 r.setLeft(hotSpot->startColumn()); | 963 scrollImage (_screenWindow->scrollCount (), _screenWindow->scrollRegion ()); |
866 r.setTop(hotSpot->startLine()); | 964 _screenWindow->resetScrollCount (); |
867 r.setRight(hotSpot->endColumn()); | 965 |
868 r.setBottom(hotSpot->endLine()); | 966 if (!_image) |
869 region |= imageToWidget(r);; | 967 { |
870 } else { | 968 // Create _image. |
871 r.setLeft(hotSpot->startColumn()); | 969 // The emitted changedContentSizeSignal also leads to getImage being recreated, so do this first. |
872 r.setTop(hotSpot->startLine()); | 970 updateImageSize (); |
873 r.setRight(_columns); | 971 } |
874 r.setBottom(hotSpot->startLine()); | 972 |
875 region |= imageToWidget(r);; | 973 Character *const newimg = _screenWindow->getImage (); |
876 for ( int line = hotSpot->startLine()+1 ; line < hotSpot->endLine() ; line++ ) { | 974 int lines = _screenWindow->windowLines (); |
877 r.setLeft(0); | 975 int columns = _screenWindow->windowColumns (); |
878 r.setTop(line); | 976 |
879 r.setRight(_columns); | 977 setScroll (_screenWindow->currentLine (), _screenWindow->lineCount ()); |
880 r.setBottom(line); | 978 |
881 region |= imageToWidget(r);; | 979 Q_ASSERT (this->_usedLines <= this->_lines); |
882 } | 980 Q_ASSERT (this->_usedColumns <= this->_columns); |
883 r.setLeft(0); | 981 |
884 r.setTop(hotSpot->endLine()); | 982 int y, x, len; |
885 r.setRight(hotSpot->endColumn()); | 983 |
886 r.setBottom(hotSpot->endLine()); | 984 QPoint tL = contentsRect ().topLeft (); |
887 region |= imageToWidget(r);; | 985 int tLx = tL.x (); |
888 } | 986 int tLy = tL.y (); |
889 } | 987 _hasBlinker = false; |
890 return region; | 988 |
891 } | 989 CharacterColor cf; // undefined |
892 | 990 CharacterColor _clipboard; // undefined |
893 void TerminalDisplay::processFilters() | 991 int cr = -1; // undefined |
894 { | 992 |
895 if (!_screenWindow) | 993 const int linesToUpdate = qMin (this->_lines, qMax (0, lines)); |
896 return; | 994 const int columnsToUpdate = qMin (this->_columns, qMax (0, columns)); |
897 | 995 |
898 QRegion preUpdateHotSpots = hotSpotRegion(); | 996 QChar *disstrU = new QChar[columnsToUpdate]; |
899 | 997 char *dirtyMask = new char[columnsToUpdate + 2]; |
900 // use _screenWindow->getImage() here rather than _image because | 998 QRegion dirtyRegion; |
901 // other classes may call processFilters() when this display's | 999 |
902 // ScreenWindow emits a scrolled() signal - which will happen before | 1000 // debugging variable, this records the number of lines that are found to |
903 // updateImage() is called on the display and therefore _image is | 1001 // be 'dirty' ( ie. have changed from the old _image to the new _image ) and |
904 // out of date at this point | 1002 // which therefore need to be repainted |
905 _filterChain->setImage( _screenWindow->getImage(), | 1003 int dirtyLineCount = 0; |
906 _screenWindow->windowLines(), | 1004 |
907 _screenWindow->windowColumns(), | 1005 for (y = 0; y < linesToUpdate; ++y) |
908 _screenWindow->getLineProperties() ); | 1006 { |
909 _filterChain->process(); | 1007 const Character *currentLine = &_image[y * this->_columns]; |
910 | 1008 const Character *const newLine = &newimg[y * columns]; |
911 QRegion postUpdateHotSpots = hotSpotRegion(); | 1009 |
912 | 1010 bool updateLine = false; |
913 update( preUpdateHotSpots | postUpdateHotSpots ); | 1011 |
914 } | 1012 // The dirty mask indicates which characters need repainting. We also |
915 | 1013 // mark surrounding neighbours dirty, in case the character exceeds |
916 void TerminalDisplay::updateImage() | 1014 // its cell boundaries |
917 { | 1015 memset (dirtyMask, 0, columnsToUpdate + 2); |
918 if ( !_screenWindow ) | 1016 |
919 return; | 1017 for (x = 0; x < columnsToUpdate; ++x) |
920 | 1018 { |
921 // optimization - scroll the existing image where possible and | 1019 if (newLine[x] != currentLine[x]) |
922 // avoid expensive text drawing for parts of the image that | 1020 { |
923 // can simply be moved up or down | 1021 dirtyMask[x] = true; |
924 scrollImage( _screenWindow->scrollCount() , | 1022 } |
925 _screenWindow->scrollRegion() ); | 1023 } |
926 _screenWindow->resetScrollCount(); | 1024 |
927 | 1025 if (!_resizing) // not while _resizing, we're expecting a paintEvent |
928 if (!_image) { | 1026 for (x = 0; x < columnsToUpdate; ++x) |
929 // Create _image. | 1027 { |
930 // The emitted changedContentSizeSignal also leads to getImage being recreated, so do this first. | 1028 _hasBlinker |= (newLine[x].rendition & RE_BLINK); |
931 updateImageSize(); | 1029 |
932 } | 1030 // Start drawing if this character or the next one differs. |
933 | 1031 // We also take the next one into account to handle the situation |
934 Character* const newimg = _screenWindow->getImage(); | 1032 // where characters exceed their cell width. |
935 int lines = _screenWindow->windowLines(); | 1033 if (dirtyMask[x]) |
936 int columns = _screenWindow->windowColumns(); | 1034 { |
937 | 1035 quint16 c = newLine[x + 0].character; |
938 setScroll( _screenWindow->currentLine() , _screenWindow->lineCount() ); | 1036 if (!c) |
939 | 1037 continue; |
940 Q_ASSERT( this->_usedLines <= this->_lines ); | 1038 int p = 0; |
941 Q_ASSERT( this->_usedColumns <= this->_columns ); | 1039 disstrU[p++] = c; //fontMap(c); |
942 | 1040 bool lineDraw = isLineChar (c); |
943 int y,x,len; | 1041 bool doubleWidth = |
944 | 1042 (x + 1 == |
945 QPoint tL = contentsRect().topLeft(); | 1043 columnsToUpdate) ? false : (newLine[x + 1].character == 0); |
946 int tLx = tL.x(); | 1044 cr = newLine[x].rendition; |
947 int tLy = tL.y(); | 1045 _clipboard = newLine[x].backgroundColor; |
948 _hasBlinker = false; | 1046 if (newLine[x].foregroundColor != cf) |
949 | 1047 cf = newLine[x].foregroundColor; |
950 CharacterColor cf; // undefined | 1048 int lln = columnsToUpdate - x; |
951 CharacterColor _clipboard; // undefined | 1049 for (len = 1; len < lln; ++len) |
952 int cr = -1; // undefined | 1050 { |
953 | 1051 const Character & ch = newLine[x + len]; |
954 const int linesToUpdate = qMin(this->_lines, qMax(0,lines )); | 1052 |
955 const int columnsToUpdate = qMin(this->_columns,qMax(0,columns)); | 1053 if (!ch.character) |
956 | 1054 continue; // Skip trailing part of multi-col chars. |
957 QChar *disstrU = new QChar[columnsToUpdate]; | 1055 |
958 char *dirtyMask = new char[columnsToUpdate+2]; | 1056 bool nextIsDoubleWidth = |
959 QRegion dirtyRegion; | 1057 (x + len + 1 == |
960 | 1058 columnsToUpdate) ? false : (newLine[x + len + |
961 // debugging variable, this records the number of lines that are found to | 1059 1].character == 0); |
962 // be 'dirty' ( ie. have changed from the old _image to the new _image ) and | 1060 |
963 // which therefore need to be repainted | 1061 if (ch.foregroundColor != cf || |
964 int dirtyLineCount = 0; | 1062 ch.backgroundColor != _clipboard || |
965 | 1063 ch.rendition != cr || |
966 for (y = 0; y < linesToUpdate; ++y) | 1064 !dirtyMask[x + len] || |
967 { | 1065 isLineChar (c) != lineDraw || |
968 const Character* currentLine = &_image[y*this->_columns]; | 1066 nextIsDoubleWidth != doubleWidth) |
969 const Character* const newLine = &newimg[y*columns]; | 1067 break; |
970 | 1068 |
971 bool updateLine = false; | 1069 disstrU[p++] = c; //fontMap(c); |
972 | 1070 } |
973 // The dirty mask indicates which characters need repainting. We also | 1071 |
974 // mark surrounding neighbours dirty, in case the character exceeds | 1072 QString unistr (disstrU, p); |
975 // its cell boundaries | 1073 |
976 memset(dirtyMask, 0, columnsToUpdate+2); | 1074 bool saveFixedFont = _fixedFont; |
977 | 1075 if (lineDraw) |
978 for( x = 0 ; x < columnsToUpdate ; ++x) | 1076 _fixedFont = false; |
979 { | 1077 if (doubleWidth) |
980 if ( newLine[x] != currentLine[x] ) | 1078 _fixedFont = false; |
981 { | 1079 |
982 dirtyMask[x] = true; | 1080 updateLine = true; |
983 } | 1081 |
984 } | 1082 _fixedFont = saveFixedFont; |
985 | 1083 x += len - 1; |
986 if (!_resizing) // not while _resizing, we're expecting a paintEvent | 1084 } |
987 for (x = 0; x < columnsToUpdate; ++x) | 1085 |
988 { | 1086 } |
989 _hasBlinker |= (newLine[x].rendition & RE_BLINK); | 1087 |
990 | 1088 //both the top and bottom halves of double height _lines must always be redrawn |
991 // Start drawing if this character or the next one differs. | 1089 //although both top and bottom halves contain the same characters, only |
992 // We also take the next one into account to handle the situation | 1090 //the top one is actually |
993 // where characters exceed their cell width. | 1091 //drawn. |
994 if (dirtyMask[x]) | 1092 if (_lineProperties.count () > y) |
995 { | 1093 updateLine |= (_lineProperties[y] & LINE_DOUBLEHEIGHT); |
996 quint16 c = newLine[x+0].character; | 1094 |
997 if ( !c ) | 1095 // if the characters on the line are different in the old and the new _image |
998 continue; | 1096 // then this line must be repainted. |
999 int p = 0; | 1097 if (updateLine) |
1000 disstrU[p++] = c; //fontMap(c); | 1098 { |
1001 bool lineDraw = isLineChar(c); | 1099 dirtyLineCount++; |
1002 bool doubleWidth = (x+1 == columnsToUpdate) ? false : (newLine[x+1].character == 0); | 1100 |
1003 cr = newLine[x].rendition; | 1101 // add the area occupied by this line to the region which needs to be |
1004 _clipboard = newLine[x].backgroundColor; | 1102 // repainted |
1005 if (newLine[x].foregroundColor != cf) cf = newLine[x].foregroundColor; | 1103 QRect dirtyRect = QRect (_leftMargin + tLx, |
1006 int lln = columnsToUpdate - x; | 1104 _topMargin + tLy + _fontHeight * y, |
1007 for (len = 1; len < lln; ++len) | 1105 _fontWidth * columnsToUpdate, |
1008 { | 1106 _fontHeight); |
1009 const Character& ch = newLine[x+len]; | 1107 |
1010 | 1108 dirtyRegion |= dirtyRect; |
1011 if (!ch.character) | 1109 } |
1012 continue; // Skip trailing part of multi-col chars. | 1110 |
1013 | 1111 // replace the line of characters in the old _image with the |
1014 bool nextIsDoubleWidth = (x+len+1 == columnsToUpdate) ? false : (newLine[x+len+1].character == 0); | 1112 // current line of the new _image |
1015 | 1113 memcpy ((void *) currentLine, (const void *) newLine, |
1016 if ( ch.foregroundColor != cf || | 1114 columnsToUpdate * sizeof (Character)); |
1017 ch.backgroundColor != _clipboard || | 1115 } |
1018 ch.rendition != cr || | 1116 |
1019 !dirtyMask[x+len] || | 1117 // if the new _image is smaller than the previous _image, then ensure that the area |
1020 isLineChar(c) != lineDraw || | 1118 // outside the new _image is cleared |
1021 nextIsDoubleWidth != doubleWidth ) | 1119 if (linesToUpdate < _usedLines) |
1022 break; | 1120 { |
1023 | 1121 dirtyRegion |= QRect (_leftMargin + tLx, |
1024 disstrU[p++] = c; //fontMap(c); | 1122 _topMargin + tLy + _fontHeight * linesToUpdate, |
1025 } | 1123 _fontWidth * this->_columns, |
1026 | 1124 _fontHeight * (_usedLines - linesToUpdate)); |
1027 QString unistr(disstrU, p); | 1125 } |
1028 | 1126 _usedLines = linesToUpdate; |
1029 bool saveFixedFont = _fixedFont; | 1127 |
1030 if (lineDraw) | 1128 if (columnsToUpdate < _usedColumns) |
1031 _fixedFont = false; | 1129 { |
1032 if (doubleWidth) | 1130 dirtyRegion |= QRect (_leftMargin + tLx + columnsToUpdate * _fontWidth, |
1033 _fixedFont = false; | 1131 _topMargin + tLy, |
1034 | 1132 _fontWidth * (_usedColumns - columnsToUpdate), |
1035 updateLine = true; | 1133 _fontHeight * this->_lines); |
1036 | 1134 } |
1037 _fixedFont = saveFixedFont; | 1135 _usedColumns = columnsToUpdate; |
1038 x += len - 1; | 1136 |
1039 } | 1137 dirtyRegion |= _inputMethodData.previousPreeditRect; |
1040 | 1138 |
1041 } | 1139 // update the parts of the display which have changed |
1042 | 1140 update (dirtyRegion); |
1043 //both the top and bottom halves of double height _lines must always be redrawn | 1141 |
1044 //although both top and bottom halves contain the same characters, only | 1142 if (_hasBlinker && !_blinkTimer->isActive ()) |
1045 //the top one is actually | 1143 _blinkTimer->start (TEXT_BLINK_DELAY); |
1046 //drawn. | 1144 if (!_hasBlinker && _blinkTimer->isActive ()) |
1047 if (_lineProperties.count() > y) | 1145 { |
1048 updateLine |= (_lineProperties[y] & LINE_DOUBLEHEIGHT); | 1146 _blinkTimer->stop (); |
1049 | 1147 _blinking = false; |
1050 // if the characters on the line are different in the old and the new _image | 1148 } |
1051 // then this line must be repainted. | 1149 delete[]dirtyMask; |
1052 if (updateLine) | 1150 delete[]disstrU; |
1053 { | 1151 |
1054 dirtyLineCount++; | 1152 } |
1055 | 1153 |
1056 // add the area occupied by this line to the region which needs to be | 1154 void |
1057 // repainted | 1155 TerminalDisplay::showResizeNotification () |
1058 QRect dirtyRect = QRect( _leftMargin+tLx , | 1156 { |
1059 _topMargin+tLy+_fontHeight*y , | 1157 if (_terminalSizeHint && isVisible ()) |
1060 _fontWidth * columnsToUpdate , | 1158 { |
1061 _fontHeight ); | 1159 if (_terminalSizeStartup) |
1062 | 1160 { |
1063 dirtyRegion |= dirtyRect; | 1161 _terminalSizeStartup = false; |
1064 } | 1162 return; |
1065 | 1163 } |
1066 // replace the line of characters in the old _image with the | 1164 if (!_resizeWidget) |
1067 // current line of the new _image | 1165 { |
1068 memcpy((void*)currentLine,(const void*)newLine,columnsToUpdate*sizeof(Character)); | 1166 _resizeWidget = new QLabel (QString ("Size: XXX x XXX"), this); |
1069 } | 1167 _resizeWidget->setMinimumWidth (_resizeWidget->fontMetrics (). |
1070 | 1168 width (QString |
1071 // if the new _image is smaller than the previous _image, then ensure that the area | 1169 ("Size: XXX x XXX"))); |
1072 // outside the new _image is cleared | 1170 _resizeWidget->setMinimumHeight (_resizeWidget->sizeHint (). |
1073 if ( linesToUpdate < _usedLines ) | 1171 height ()); |
1074 { | 1172 _resizeWidget->setAlignment (Qt::AlignCenter); |
1075 dirtyRegion |= QRect( _leftMargin+tLx , | 1173 |
1076 _topMargin+tLy+_fontHeight*linesToUpdate , | 1174 _resizeWidget-> |
1077 _fontWidth * this->_columns , | 1175 setStyleSheet |
1078 _fontHeight * (_usedLines-linesToUpdate) ); | 1176 ("background-color:palette(window);border-style:solid;border-width:1px;border-color:palette(dark)"); |
1079 } | 1177 |
1080 _usedLines = linesToUpdate; | 1178 _resizeTimer = new QTimer (this); |
1081 | 1179 _resizeTimer->setSingleShot (true); |
1082 if ( columnsToUpdate < _usedColumns ) | 1180 connect (_resizeTimer, SIGNAL (timeout ()), _resizeWidget, |
1083 { | 1181 SLOT (hide ())); |
1084 dirtyRegion |= QRect( _leftMargin+tLx+columnsToUpdate*_fontWidth , | 1182 } |
1085 _topMargin+tLy , | 1183 QString sizeStr = QString ("Size: %1 x %2").arg (_columns).arg (_lines); |
1086 _fontWidth * (_usedColumns-columnsToUpdate) , | 1184 _resizeWidget->setText (sizeStr); |
1087 _fontHeight * this->_lines ); | 1185 _resizeWidget->move ((width () - _resizeWidget->width ()) / 2, |
1088 } | 1186 (height () - _resizeWidget->height ()) / 2 + 20); |
1089 _usedColumns = columnsToUpdate; | 1187 _resizeWidget->show (); |
1090 | 1188 _resizeTimer->start (1000); |
1091 dirtyRegion |= _inputMethodData.previousPreeditRect; | 1189 } |
1092 | 1190 } |
1093 // update the parts of the display which have changed | 1191 |
1094 update(dirtyRegion); | 1192 void |
1095 | 1193 TerminalDisplay::setBlinkingCursor (bool blink) |
1096 if ( _hasBlinker && !_blinkTimer->isActive()) _blinkTimer->start( TEXT_BLINK_DELAY ); | 1194 { |
1097 if (!_hasBlinker && _blinkTimer->isActive()) { _blinkTimer->stop(); _blinking = false; } | 1195 _hasBlinkingCursor = blink; |
1098 delete[] dirtyMask; | 1196 |
1099 delete[] disstrU; | 1197 if (blink && !_blinkCursorTimer->isActive ()) |
1100 | 1198 _blinkCursorTimer->start (QApplication::cursorFlashTime () / 2); |
1101 } | 1199 |
1102 | 1200 if (!blink && _blinkCursorTimer->isActive ()) |
1103 void TerminalDisplay::showResizeNotification() | 1201 { |
1104 { | 1202 _blinkCursorTimer->stop (); |
1105 if (_terminalSizeHint && isVisible()) | 1203 if (_cursorBlinking) |
1106 { | 1204 blinkCursorEvent (); |
1107 if (_terminalSizeStartup) { | 1205 else |
1108 _terminalSizeStartup=false; | 1206 _cursorBlinking = false; |
1109 return; | 1207 } |
1110 } | 1208 } |
1111 if (!_resizeWidget) | 1209 |
1112 { | 1210 void |
1113 _resizeWidget = new QLabel(QString("Size: XXX x XXX"), this); | 1211 TerminalDisplay::setBlinkingTextEnabled (bool blink) |
1114 _resizeWidget->setMinimumWidth(_resizeWidget->fontMetrics().width(QString("Size: XXX x XXX"))); | 1212 { |
1115 _resizeWidget->setMinimumHeight(_resizeWidget->sizeHint().height()); | 1213 _allowBlinkingText = blink; |
1116 _resizeWidget->setAlignment(Qt::AlignCenter); | 1214 |
1117 | 1215 if (blink && !_blinkTimer->isActive ()) |
1118 _resizeWidget->setStyleSheet("background-color:palette(window);border-style:solid;border-width:1px;border-color:palette(dark)"); | 1216 _blinkTimer->start (TEXT_BLINK_DELAY); |
1119 | 1217 |
1120 _resizeTimer = new QTimer(this); | 1218 if (!blink && _blinkTimer->isActive ()) |
1121 _resizeTimer->setSingleShot(true); | 1219 { |
1122 connect(_resizeTimer, SIGNAL(timeout()), _resizeWidget, SLOT(hide())); | 1220 _blinkTimer->stop (); |
1123 } | 1221 _blinking = false; |
1124 QString sizeStr = QString("Size: %1 x %2").arg(_columns).arg(_lines); | 1222 } |
1125 _resizeWidget->setText(sizeStr); | 1223 } |
1126 _resizeWidget->move((width()-_resizeWidget->width())/2, | 1224 |
1127 (height()-_resizeWidget->height())/2+20); | 1225 void |
1128 _resizeWidget->show(); | 1226 TerminalDisplay::focusOutEvent (QFocusEvent *) |
1129 _resizeTimer->start(1000); | 1227 { |
1130 } | 1228 // trigger a repaint of the cursor so that it is both visible (in case |
1131 } | 1229 // it was hidden during blinking) |
1132 | 1230 // and drawn in a focused out state |
1133 void TerminalDisplay::setBlinkingCursor(bool blink) | 1231 _cursorBlinking = false; |
1134 { | 1232 updateCursor (); |
1135 _hasBlinkingCursor=blink; | 1233 |
1136 | 1234 _blinkCursorTimer->stop (); |
1137 if (blink && !_blinkCursorTimer->isActive()) | 1235 if (_blinking) |
1138 _blinkCursorTimer->start(QApplication::cursorFlashTime() / 2); | 1236 blinkEvent (); |
1139 | 1237 |
1140 if (!blink && _blinkCursorTimer->isActive()) | 1238 _blinkTimer->stop (); |
1141 { | 1239 } |
1142 _blinkCursorTimer->stop(); | 1240 |
1143 if (_cursorBlinking) | 1241 void |
1144 blinkCursorEvent(); | 1242 TerminalDisplay::focusInEvent (QFocusEvent *) |
1145 else | 1243 { |
1146 _cursorBlinking = false; | 1244 if (_hasBlinkingCursor) |
1147 } | 1245 { |
1148 } | 1246 _blinkCursorTimer->start (); |
1149 | 1247 } |
1150 void TerminalDisplay::setBlinkingTextEnabled(bool blink) | 1248 updateCursor (); |
1151 { | 1249 |
1152 _allowBlinkingText = blink; | 1250 if (_hasBlinker) |
1153 | 1251 _blinkTimer->start (); |
1154 if (blink && !_blinkTimer->isActive()) | 1252 } |
1155 _blinkTimer->start(TEXT_BLINK_DELAY); | 1253 |
1156 | 1254 void |
1157 if (!blink && _blinkTimer->isActive()) | 1255 TerminalDisplay::paintEvent (QPaintEvent * pe) |
1158 { | 1256 { |
1159 _blinkTimer->stop(); | 1257 QPainter paint (this); |
1160 _blinking = false; | 1258 |
1161 } | 1259 foreach (const QRect & rect, (pe->region () & contentsRect ()).rects ()) |
1162 } | 1260 { |
1163 | 1261 drawBackground (paint, rect, palette ().background ().color (), |
1164 void TerminalDisplay::focusOutEvent(QFocusEvent*) | 1262 true /* use opacity setting */ ); |
1165 { | 1263 drawContents (paint, rect); |
1166 // trigger a repaint of the cursor so that it is both visible (in case | 1264 } |
1167 // it was hidden during blinking) | 1265 drawInputMethodPreeditString (paint, preeditRect ()); |
1168 // and drawn in a focused out state | 1266 paintFilters (paint); |
1169 _cursorBlinking = false; | 1267 } |
1170 updateCursor(); | 1268 |
1171 | 1269 QPoint |
1172 _blinkCursorTimer->stop(); | 1270 TerminalDisplay::cursorPosition () const |
1173 if (_blinking) | 1271 { |
1174 blinkEvent(); | 1272 if (_screenWindow) |
1175 | 1273 return _screenWindow->cursorPosition (); |
1176 _blinkTimer->stop(); | 1274 else |
1177 } | 1275 return QPoint (0, 0); |
1178 void TerminalDisplay::focusInEvent(QFocusEvent*) | 1276 } |
1179 { | 1277 |
1180 if (_hasBlinkingCursor) | 1278 QRect |
1181 { | 1279 TerminalDisplay::preeditRect () const |
1182 _blinkCursorTimer->start(); | 1280 { |
1183 } | 1281 const int preeditLength = string_width (_inputMethodData.preeditString); |
1184 updateCursor(); | 1282 |
1185 | 1283 if (preeditLength == 0) |
1186 if (_hasBlinker) | 1284 return QRect (); |
1187 _blinkTimer->start(); | 1285 |
1188 } | 1286 return QRect (_leftMargin + _fontWidth * cursorPosition ().x (), |
1189 | 1287 _topMargin + _fontHeight * cursorPosition ().y (), |
1190 void TerminalDisplay::paintEvent( QPaintEvent* pe ) | 1288 _fontWidth * preeditLength, _fontHeight); |
1191 { | 1289 } |
1192 QPainter paint(this); | 1290 |
1193 | 1291 void |
1194 foreach (const QRect &rect, (pe->region() & contentsRect()).rects()) | 1292 TerminalDisplay::drawInputMethodPreeditString (QPainter & painter, |
1195 { | 1293 const QRect & rect) |
1196 drawBackground(paint,rect,palette().background().color(), | 1294 { |
1197 true /* use opacity setting */); | 1295 if (_inputMethodData.preeditString.isEmpty ()) |
1198 drawContents(paint, rect); | 1296 return; |
1199 } | 1297 |
1200 drawInputMethodPreeditString(paint,preeditRect()); | 1298 const QPoint cursorPos = cursorPosition (); |
1201 paintFilters(paint); | 1299 |
1202 } | 1300 bool invertColors = false; |
1203 | 1301 const QColor background = _colorTable[DEFAULT_BACK_COLOR].color; |
1204 QPoint TerminalDisplay::cursorPosition() const | 1302 const QColor foreground = _colorTable[DEFAULT_FORE_COLOR].color; |
1205 { | 1303 const Character *style = &_image[loc (cursorPos.x (), cursorPos.y ())]; |
1206 if (_screenWindow) | 1304 |
1207 return _screenWindow->cursorPosition(); | 1305 drawBackground (painter, rect, background, true); |
1208 else | 1306 drawCursor (painter, rect, foreground, background, invertColors); |
1209 return QPoint(0,0); | 1307 drawCharacters (painter, rect, _inputMethodData.preeditString, style, |
1210 } | 1308 invertColors); |
1211 | 1309 |
1212 QRect TerminalDisplay::preeditRect() const | 1310 _inputMethodData.previousPreeditRect = rect; |
1213 { | 1311 } |
1214 const int preeditLength = string_width(_inputMethodData.preeditString); | 1312 |
1215 | 1313 FilterChain * |
1216 if ( preeditLength == 0 ) | 1314 TerminalDisplay::filterChain () const |
1217 return QRect(); | 1315 { |
1218 | 1316 return _filterChain; |
1219 return QRect(_leftMargin + _fontWidth*cursorPosition().x(), | 1317 } |
1220 _topMargin + _fontHeight*cursorPosition().y(), | 1318 |
1221 _fontWidth*preeditLength, | 1319 void |
1222 _fontHeight); | 1320 TerminalDisplay::paintFilters (QPainter & painter) |
1223 } | 1321 { |
1224 | 1322 // get color of character under mouse and use it to draw |
1225 void TerminalDisplay::drawInputMethodPreeditString(QPainter& painter , const QRect& rect) | 1323 // lines for filters |
1226 { | 1324 QPoint cursorPos = mapFromGlobal (QCursor::pos ()); |
1227 if ( _inputMethodData.preeditString.isEmpty() ) | 1325 int cursorLine; |
1228 return; | 1326 int cursorColumn; |
1229 | 1327 int scrollBarWidth = |
1230 const QPoint cursorPos = cursorPosition(); | 1328 (_scrollbarLocation == ScrollBarLeft) ? _scrollBar->width () : 0; |
1231 | 1329 |
1232 bool invertColors = false; | 1330 getCharacterPosition (cursorPos, cursorLine, cursorColumn); |
1233 const QColor background = _colorTable[DEFAULT_BACK_COLOR].color; | 1331 Character cursorCharacter = _image[loc (cursorColumn, cursorLine)]; |
1234 const QColor foreground = _colorTable[DEFAULT_FORE_COLOR].color; | 1332 |
1235 const Character* style = &_image[loc(cursorPos.x(),cursorPos.y())]; | 1333 painter. |
1236 | 1334 setPen (QPen (cursorCharacter.foregroundColor.color (colorTable ()))); |
1237 drawBackground(painter,rect,background,true); | 1335 |
1238 drawCursor(painter,rect,foreground,background,invertColors); | 1336 // iterate over hotspots identified by the display's currently active filters |
1239 drawCharacters(painter,rect,_inputMethodData.preeditString,style,invertColors); | 1337 // and draw appropriate visuals to indicate the presence of the hotspot |
1240 | 1338 |
1241 _inputMethodData.previousPreeditRect = rect; | 1339 QList < Filter::HotSpot * >spots = _filterChain->hotSpots (); |
1242 } | 1340 QListIterator < Filter::HotSpot * >iter (spots); |
1243 | 1341 while (iter.hasNext ()) |
1244 FilterChain* TerminalDisplay::filterChain() const | 1342 { |
1245 { | 1343 Filter::HotSpot * spot = iter.next (); |
1246 return _filterChain; | 1344 |
1247 } | 1345 QRegion region; |
1248 | 1346 if (spot->type () == Filter::HotSpot::Link) |
1249 void TerminalDisplay::paintFilters(QPainter& painter) | 1347 { |
1250 { | 1348 QRect r; |
1251 // get color of character under mouse and use it to draw | 1349 if (spot->startLine () == spot->endLine ()) |
1252 // lines for filters | 1350 { |
1253 QPoint cursorPos = mapFromGlobal(QCursor::pos()); | 1351 r.setCoords (spot->startColumn () * _fontWidth + 1 + |
1254 int cursorLine; | 1352 scrollBarWidth, |
1255 int cursorColumn; | 1353 spot->startLine () * _fontHeight + 1, |
1256 int scrollBarWidth = (_scrollbarLocation == ScrollBarLeft) ? _scrollBar->width() : 0; | 1354 (spot->endColumn () - 1) * _fontWidth - 1 + |
1257 | 1355 scrollBarWidth, |
1258 getCharacterPosition( cursorPos , cursorLine , cursorColumn ); | 1356 (spot->endLine () + 1) * _fontHeight - 1); |
1259 Character cursorCharacter = _image[loc(cursorColumn,cursorLine)]; | 1357 region |= r; |
1260 | 1358 } |
1261 painter.setPen( QPen(cursorCharacter.foregroundColor.color(colorTable())) ); | 1359 else |
1262 | 1360 { |
1263 // iterate over hotspots identified by the display's currently active filters | 1361 r.setCoords (spot->startColumn () * _fontWidth + 1 + |
1264 // and draw appropriate visuals to indicate the presence of the hotspot | 1362 scrollBarWidth, |
1265 | 1363 spot->startLine () * _fontHeight + 1, |
1266 QList<Filter::HotSpot*> spots = _filterChain->hotSpots(); | 1364 (_columns - 1) * _fontWidth - 1 + scrollBarWidth, |
1267 QListIterator<Filter::HotSpot*> iter(spots); | 1365 (spot->startLine () + 1) * _fontHeight - 1); |
1268 while (iter.hasNext()) | 1366 region |= r; |
1269 { | 1367 for (int line = spot->startLine () + 1; line < spot->endLine (); |
1270 Filter::HotSpot* spot = iter.next(); | 1368 line++) |
1271 | 1369 { |
1272 QRegion region; | 1370 r.setCoords (0 * _fontWidth + 1 + scrollBarWidth, |
1273 if ( spot->type() == Filter::HotSpot::Link ) { | 1371 line * _fontHeight + 1, |
1274 QRect r; | 1372 (_columns - 1) * _fontWidth - 1 + |
1275 if (spot->startLine()==spot->endLine()) { | 1373 scrollBarWidth, (line + 1) * _fontHeight - 1); |
1276 r.setCoords( spot->startColumn()*_fontWidth + 1 + scrollBarWidth, | 1374 region |= r; |
1277 spot->startLine()*_fontHeight + 1, | 1375 } |
1278 (spot->endColumn()-1)*_fontWidth - 1 + scrollBarWidth, | 1376 r.setCoords (0 * _fontWidth + 1 + scrollBarWidth, |
1279 (spot->endLine()+1)*_fontHeight - 1 ); | 1377 spot->endLine () * _fontHeight + 1, |
1280 region |= r; | 1378 (spot->endColumn () - 1) * _fontWidth - 1 + |
1281 } else { | 1379 scrollBarWidth, |
1282 r.setCoords( spot->startColumn()*_fontWidth + 1 + scrollBarWidth, | 1380 (spot->endLine () + 1) * _fontHeight - 1); |
1283 spot->startLine()*_fontHeight + 1, | 1381 region |= r; |
1284 (_columns-1)*_fontWidth - 1 + scrollBarWidth, | 1382 } |
1285 (spot->startLine()+1)*_fontHeight - 1 ); | 1383 } |
1286 region |= r; | 1384 |
1287 for ( int line = spot->startLine()+1 ; line < spot->endLine() ; line++ ) { | 1385 for (int line = spot->startLine (); line <= spot->endLine (); line++) |
1288 r.setCoords( 0*_fontWidth + 1 + scrollBarWidth, | 1386 { |
1289 line*_fontHeight + 1, | 1387 int startColumn = 0; |
1290 (_columns-1)*_fontWidth - 1 + scrollBarWidth, | 1388 int endColumn = _columns - 1; // TODO use number of _columns which are actually |
1291 (line+1)*_fontHeight - 1 ); | 1389 // occupied on this line rather than the width of the |
1292 region |= r; | 1390 // display in _columns |
1293 } | 1391 |
1294 r.setCoords( 0*_fontWidth + 1 + scrollBarWidth, | 1392 // ignore whitespace at the end of the lines |
1295 spot->endLine()*_fontHeight + 1, | 1393 while (QChar (_image[loc (endColumn, line)].character).isSpace () |
1296 (spot->endColumn()-1)*_fontWidth - 1 + scrollBarWidth, | 1394 && endColumn > 0) |
1297 (spot->endLine()+1)*_fontHeight - 1 ); | 1395 endColumn--; |
1298 region |= r; | 1396 |
1299 } | 1397 // increment here because the column which we want to set 'endColumn' to |
1300 } | 1398 // is the first whitespace character at the end of the line |
1301 | 1399 endColumn++; |
1302 for ( int line = spot->startLine() ; line <= spot->endLine() ; line++ ) | 1400 |
1303 { | 1401 if (line == spot->startLine ()) |
1304 int startColumn = 0; | 1402 startColumn = spot->startColumn (); |
1305 int endColumn = _columns-1; // TODO use number of _columns which are actually | 1403 if (line == spot->endLine ()) |
1306 // occupied on this line rather than the width of the | 1404 endColumn = spot->endColumn (); |
1307 // display in _columns | 1405 |
1308 | 1406 // subtract one pixel from |
1309 // ignore whitespace at the end of the lines | 1407 // the right and bottom so that |
1310 while ( QChar(_image[loc(endColumn,line)].character).isSpace() && endColumn > 0 ) | 1408 // we do not overdraw adjacent |
1311 endColumn--; | 1409 // hotspots |
1312 | 1410 // |
1313 // increment here because the column which we want to set 'endColumn' to | 1411 // subtracting one pixel from all sides also prevents an edge case where |
1314 // is the first whitespace character at the end of the line | 1412 // moving the mouse outside a link could still leave it underlined |
1315 endColumn++; | 1413 // because the check below for the position of the cursor |
1316 | 1414 // finds it on the border of the target area |
1317 if ( line == spot->startLine() ) | 1415 QRect r; |
1318 startColumn = spot->startColumn(); | 1416 r.setCoords (startColumn * _fontWidth + 1 + scrollBarWidth, |
1319 if ( line == spot->endLine() ) | 1417 line * _fontHeight + 1, |
1320 endColumn = spot->endColumn(); | 1418 endColumn * _fontWidth - 1 + scrollBarWidth, |
1321 | 1419 (line + 1) * _fontHeight - 1); |
1322 // subtract one pixel from | 1420 // Underline link hotspots |
1323 // the right and bottom so that | 1421 if (spot->type () == Filter::HotSpot::Link) |
1324 // we do not overdraw adjacent | 1422 { |
1325 // hotspots | 1423 QFontMetrics metrics (font ()); |
1326 // | 1424 |
1327 // subtracting one pixel from all sides also prevents an edge case where | 1425 // find the baseline (which is the invisible line that the characters in the font sit on, |
1328 // moving the mouse outside a link could still leave it underlined | 1426 // with some having tails dangling below) |
1329 // because the check below for the position of the cursor | 1427 int baseline = r.bottom () - metrics.descent (); |
1330 // finds it on the border of the target area | 1428 // find the position of the underline below that |
1331 QRect r; | 1429 int underlinePos = baseline + metrics.underlinePos (); |
1332 r.setCoords( startColumn*_fontWidth + 1 + scrollBarWidth, | 1430 if (region.contains (mapFromGlobal (QCursor::pos ()))) |
1333 line*_fontHeight + 1, | 1431 { |
1334 endColumn*_fontWidth - 1 + scrollBarWidth, | 1432 painter.drawLine (r.left (), underlinePos, |
1335 (line+1)*_fontHeight - 1 ); | 1433 r.right (), underlinePos); |
1336 // Underline link hotspots | 1434 } |
1337 if ( spot->type() == Filter::HotSpot::Link ) | 1435 } |
1338 { | 1436 // Marker hotspots simply have a transparent rectanglular shape |
1339 QFontMetrics metrics(font()); | 1437 // drawn on top of them |
1340 | 1438 else if (spot->type () == Filter::HotSpot::Marker) |
1341 // find the baseline (which is the invisible line that the characters in the font sit on, | 1439 { |
1342 // with some having tails dangling below) | 1440 //TODO - Do not use a hardcoded colour for this |
1343 int baseline = r.bottom() - metrics.descent(); | 1441 painter.fillRect (r, QBrush (QColor (255, 0, 0, 120))); |
1344 // find the position of the underline below that | 1442 } |
1345 int underlinePos = baseline + metrics.underlinePos(); | 1443 } |
1346 if ( region.contains( mapFromGlobal(QCursor::pos()) ) ){ | 1444 } |
1347 painter.drawLine( r.left() , underlinePos , | 1445 } |
1348 r.right() , underlinePos ); | 1446 |
1349 } | 1447 void |
1350 } | 1448 TerminalDisplay::drawContents (QPainter & paint, const QRect & rect) |
1351 // Marker hotspots simply have a transparent rectanglular shape | 1449 { |
1352 // drawn on top of them | 1450 QPoint tL = contentsRect ().topLeft (); |
1353 else if ( spot->type() == Filter::HotSpot::Marker ) | 1451 int tLx = tL.x (); |
1354 { | 1452 int tLy = tL.y (); |
1355 //TODO - Do not use a hardcoded colour for this | 1453 |
1356 painter.fillRect(r,QBrush(QColor(255,0,0,120))); | 1454 int lux = |
1357 } | 1455 qMin (_usedColumns - 1, |
1358 } | 1456 qMax (0, (rect.left () - tLx - _leftMargin) / _fontWidth)); |
1359 } | 1457 int luy = |
1360 } | 1458 qMin (_usedLines - 1, |
1361 void TerminalDisplay::drawContents(QPainter &paint, const QRect &rect) | 1459 qMax (0, (rect.top () - tLy - _topMargin) / _fontHeight)); |
1362 { | 1460 int rlx = |
1363 QPoint tL = contentsRect().topLeft(); | 1461 qMin (_usedColumns - 1, |
1364 int tLx = tL.x(); | 1462 qMax (0, (rect.right () - tLx - _leftMargin) / _fontWidth)); |
1365 int tLy = tL.y(); | 1463 int rly = |
1366 | 1464 qMin (_usedLines - 1, |
1367 int lux = qMin(_usedColumns-1, qMax(0,(rect.left() - tLx - _leftMargin ) / _fontWidth)); | 1465 qMax (0, (rect.bottom () - tLy - _topMargin) / _fontHeight)); |
1368 int luy = qMin(_usedLines-1, qMax(0,(rect.top() - tLy - _topMargin ) / _fontHeight)); | 1466 |
1369 int rlx = qMin(_usedColumns-1, qMax(0,(rect.right() - tLx - _leftMargin ) / _fontWidth)); | 1467 const int bufferSize = _usedColumns; |
1370 int rly = qMin(_usedLines-1, qMax(0,(rect.bottom() - tLy - _topMargin ) / _fontHeight)); | 1468 QString unistr; |
1371 | 1469 unistr.reserve (bufferSize); |
1372 const int bufferSize = _usedColumns; | 1470 for (int y = luy; y <= rly; y++) |
1373 QString unistr; | 1471 { |
1374 unistr.reserve(bufferSize); | 1472 quint16 c = _image[loc (lux, y)].character; |
1375 for (int y = luy; y <= rly; y++) | 1473 int x = lux; |
1376 { | 1474 if (!c && x) |
1377 quint16 c = _image[loc(lux,y)].character; | 1475 x--; // Search for start of multi-column character |
1378 int x = lux; | 1476 for (; x <= rlx; x++) |
1379 if(!c && x) | 1477 { |
1380 x--; // Search for start of multi-column character | 1478 int len = 1; |
1381 for (; x <= rlx; x++) | 1479 int p = 0; |
1382 { | 1480 |
1383 int len = 1; | 1481 // reset our buffer to the maximal size |
1384 int p = 0; | 1482 unistr.resize (bufferSize); |
1385 | 1483 QChar *disstrU = unistr.data (); |
1386 // reset our buffer to the maximal size | 1484 |
1387 unistr.resize(bufferSize); | 1485 // is this a single character or a sequence of characters ? |
1388 QChar *disstrU = unistr.data(); | 1486 if (_image[loc (x, y)].rendition & RE_EXTENDED_CHAR) |
1389 | 1487 { |
1390 // is this a single character or a sequence of characters ? | 1488 // sequence of characters |
1391 if ( _image[loc(x,y)].rendition & RE_EXTENDED_CHAR ) | 1489 ushort extendedCharLength = 0; |
1392 { | 1490 ushort *chars = |
1393 // sequence of characters | 1491 ExtendedCharTable::instance. |
1394 ushort extendedCharLength = 0; | 1492 lookupExtendedChar (_image[loc (x, y)].charSequence, |
1395 ushort* chars = ExtendedCharTable::instance | 1493 extendedCharLength); |
1396 .lookupExtendedChar(_image[loc(x,y)].charSequence,extendedCharLength); | 1494 for (int index = 0; index < extendedCharLength; index++) |
1397 for ( int index = 0 ; index < extendedCharLength ; index++ ) | 1495 { |
1398 { | 1496 Q_ASSERT (p < bufferSize); |
1399 Q_ASSERT( p < bufferSize ); | 1497 disstrU[p++] = chars[index]; |
1400 disstrU[p++] = chars[index]; | 1498 } |
1401 } | 1499 } |
1402 } | 1500 else |
1403 else | 1501 { |
1404 { | 1502 // single character |
1405 // single character | 1503 c = _image[loc (x, y)].character; |
1406 c = _image[loc(x,y)].character; | 1504 if (c) |
1407 if (c) | 1505 { |
1408 { | 1506 Q_ASSERT (p < bufferSize); |
1409 Q_ASSERT( p < bufferSize ); | 1507 disstrU[p++] = c; //fontMap(c); |
1410 disstrU[p++] = c; //fontMap(c); | 1508 } |
1411 } | 1509 } |
1412 } | 1510 |
1413 | 1511 bool lineDraw = isLineChar (c); |
1414 bool lineDraw = isLineChar(c); | 1512 bool doubleWidth = |
1415 bool doubleWidth = (_image[ qMin(loc(x,y)+1,_imageSize) ].character == 0); | 1513 (_image[qMin (loc (x, y) + 1, _imageSize)].character == 0); |
1416 CharacterColor currentForeground = _image[loc(x,y)].foregroundColor; | 1514 CharacterColor currentForeground = |
1417 CharacterColor currentBackground = _image[loc(x,y)].backgroundColor; | 1515 _image[loc (x, y)].foregroundColor; |
1418 quint8 currentRendition = _image[loc(x,y)].rendition; | 1516 CharacterColor currentBackground = |
1419 | 1517 _image[loc (x, y)].backgroundColor; |
1420 while (x+len <= rlx && | 1518 quint8 currentRendition = _image[loc (x, y)].rendition; |
1421 _image[loc(x+len,y)].foregroundColor == currentForeground && | 1519 |
1422 _image[loc(x+len,y)].backgroundColor == currentBackground && | 1520 while (x + len <= rlx && _image[loc (x + len, y)].foregroundColor == currentForeground && _image[loc (x + len, y)].backgroundColor == currentBackground && _image[loc (x + len, y)].rendition == currentRendition && (_image[qMin (loc (x + len, y) + 1, _imageSize)].character == 0) == doubleWidth && isLineChar (c = _image[loc (x + len, y)].character) == lineDraw) // Assignment! |
1423 _image[loc(x+len,y)].rendition == currentRendition && | 1521 { |
1424 (_image[ qMin(loc(x+len,y)+1,_imageSize) ].character == 0) == doubleWidth && | 1522 if (c) |
1425 isLineChar( c = _image[loc(x+len,y)].character) == lineDraw) // Assignment! | 1523 disstrU[p++] = c; //fontMap(c); |
1426 { | 1524 if (doubleWidth) // assert((_image[loc(x+len,y)+1].character == 0)), see above if condition |
1427 if (c) | 1525 len++; // Skip trailing part of multi-column character |
1428 disstrU[p++] = c; //fontMap(c); | 1526 len++; |
1429 if (doubleWidth) // assert((_image[loc(x+len,y)+1].character == 0)), see above if condition | 1527 } |
1430 len++; // Skip trailing part of multi-column character | 1528 if ((x + len < _usedColumns) |
1431 len++; | 1529 && (!_image[loc (x + len, y)].character)) |
1432 } | 1530 len++; // Adjust for trailing part of multi-column character |
1433 if ((x+len < _usedColumns) && (!_image[loc(x+len,y)].character)) | 1531 |
1434 len++; // Adjust for trailing part of multi-column character | 1532 bool save__fixedFont = _fixedFont; |
1435 | 1533 if (lineDraw) |
1436 bool save__fixedFont = _fixedFont; | 1534 _fixedFont = false; |
1437 if (lineDraw) | 1535 if (doubleWidth) |
1438 _fixedFont = false; | 1536 _fixedFont = false; |
1439 if (doubleWidth) | 1537 unistr.resize (p); |
1440 _fixedFont = false; | 1538 |
1441 unistr.resize(p); | 1539 // Create a text scaling matrix for double width and double height lines. |
1442 | 1540 QMatrix textScale; |
1443 // Create a text scaling matrix for double width and double height lines. | 1541 |
1444 QMatrix textScale; | 1542 if (y < _lineProperties.size ()) |
1445 | 1543 { |
1446 if (y < _lineProperties.size()) | 1544 if (_lineProperties[y] & LINE_DOUBLEWIDTH) |
1447 { | 1545 textScale.scale (2, 1); |
1448 if (_lineProperties[y] & LINE_DOUBLEWIDTH) | 1546 |
1449 textScale.scale(2,1); | 1547 if (_lineProperties[y] & LINE_DOUBLEHEIGHT) |
1450 | 1548 textScale.scale (1, 2); |
1451 if (_lineProperties[y] & LINE_DOUBLEHEIGHT) | 1549 } |
1452 textScale.scale(1,2); | 1550 |
1453 } | 1551 //Apply text scaling matrix. |
1454 | 1552 paint.setWorldMatrix (textScale, true); |
1455 //Apply text scaling matrix. | 1553 |
1456 paint.setWorldMatrix(textScale, true); | 1554 //calculate the area in which the text will be drawn |
1457 | 1555 QRect textArea = |
1458 //calculate the area in which the text will be drawn | 1556 QRect (_leftMargin + tLx + _fontWidth * x, |
1459 QRect textArea = QRect( _leftMargin+tLx+_fontWidth*x , _topMargin+tLy+_fontHeight*y , _fontWidth*len , _fontHeight); | 1557 _topMargin + tLy + _fontHeight * y, _fontWidth * len, |
1460 | 1558 _fontHeight); |
1461 //move the calculated area to take account of scaling applied to the painter. | 1559 |
1462 //the position of the area from the origin (0,0) is scaled | 1560 //move the calculated area to take account of scaling applied to the painter. |
1463 //by the opposite of whatever | 1561 //the position of the area from the origin (0,0) is scaled |
1464 //transformation has been applied to the painter. this ensures that | 1562 //by the opposite of whatever |
1465 //painting does actually start from textArea.topLeft() | 1563 //transformation has been applied to the painter. this ensures that |
1466 //(instead of textArea.topLeft() * painter-scale) | 1564 //painting does actually start from textArea.topLeft() |
1467 textArea.moveTopLeft( textScale.inverted().map(textArea.topLeft()) ); | 1565 //(instead of textArea.topLeft() * painter-scale) |
1468 | 1566 textArea.moveTopLeft (textScale.inverted (). |
1469 //paint text fragment | 1567 map (textArea.topLeft ())); |
1470 drawTextFragment( paint, | 1568 |
1471 textArea, | 1569 //paint text fragment |
1472 unistr, | 1570 drawTextFragment (paint, textArea, unistr, &_image[loc (x, y)]); //, |
1473 &_image[loc(x,y)] ); //, | 1571 //0, |
1474 //0, | 1572 //!_isPrinting ); |
1475 //!_isPrinting ); | 1573 |
1476 | 1574 _fixedFont = save__fixedFont; |
1477 _fixedFont = save__fixedFont; | 1575 |
1478 | 1576 //reset back to single-width, single-height _lines |
1479 //reset back to single-width, single-height _lines | 1577 paint.setWorldMatrix (textScale.inverted (), true); |
1480 paint.setWorldMatrix(textScale.inverted(), true); | 1578 |
1481 | 1579 if (y < _lineProperties.size () - 1) |
1482 if (y < _lineProperties.size()-1) | 1580 { |
1483 { | 1581 //double-height _lines are represented by two adjacent _lines |
1484 //double-height _lines are represented by two adjacent _lines | 1582 //containing the same characters |
1485 //containing the same characters | 1583 //both _lines will have the LINE_DOUBLEHEIGHT attribute. |
1486 //both _lines will have the LINE_DOUBLEHEIGHT attribute. | 1584 //If the current line has the LINE_DOUBLEHEIGHT attribute, |
1487 //If the current line has the LINE_DOUBLEHEIGHT attribute, | 1585 //we can therefore skip the next line |
1488 //we can therefore skip the next line | 1586 if (_lineProperties[y] & LINE_DOUBLEHEIGHT) |
1489 if (_lineProperties[y] & LINE_DOUBLEHEIGHT) | 1587 y++; |
1490 y++; | 1588 } |
1491 } | 1589 |
1492 | 1590 x += len - 1; |
1493 x += len - 1; | 1591 } |
1494 } | 1592 } |
1495 } | 1593 } |
1496 } | 1594 |
1497 | 1595 void |
1498 void TerminalDisplay::blinkEvent() | 1596 TerminalDisplay::blinkEvent () |
1499 { | 1597 { |
1500 if (!_allowBlinkingText) return; | 1598 if (!_allowBlinkingText) |
1501 | 1599 return; |
1502 _blinking = !_blinking; | 1600 |
1503 | 1601 _blinking = !_blinking; |
1504 //TODO: Optimize to only repaint the areas of the widget | 1602 |
1505 // where there is blinking text | 1603 //TODO: Optimize to only repaint the areas of the widget |
1506 // rather than repainting the whole widget. | 1604 // where there is blinking text |
1507 update(); | 1605 // rather than repainting the whole widget. |
1508 } | 1606 update (); |
1509 | 1607 } |
1510 QRect TerminalDisplay::imageToWidget(const QRect& imageArea) const | 1608 |
1511 { | 1609 QRect |
1512 QRect result; | 1610 TerminalDisplay::imageToWidget (const QRect & imageArea) const |
1513 result.setLeft( _leftMargin + _fontWidth * imageArea.left() ); | 1611 { |
1514 result.setTop( _topMargin + _fontHeight * imageArea.top() ); | 1612 QRect result; |
1515 result.setWidth( _fontWidth * imageArea.width() ); | 1613 result.setLeft (_leftMargin + _fontWidth * imageArea.left ()); |
1516 result.setHeight( _fontHeight * imageArea.height() ); | 1614 result.setTop (_topMargin + _fontHeight * imageArea.top ()); |
1517 | 1615 result.setWidth (_fontWidth * imageArea.width ()); |
1518 return result; | 1616 result.setHeight (_fontHeight * imageArea.height ()); |
1519 } | 1617 |
1520 | 1618 return result; |
1521 void TerminalDisplay::updateCursor() | 1619 } |
1522 { | 1620 |
1523 QRect cursorRect = imageToWidget( QRect(cursorPosition(),QSize(1,1)) ); | 1621 void |
1524 update(cursorRect); | 1622 TerminalDisplay::updateCursor () |
1525 } | 1623 { |
1526 | 1624 QRect cursorRect = imageToWidget (QRect (cursorPosition (), QSize (1, 1))); |
1527 void TerminalDisplay::blinkCursorEvent() | 1625 update (cursorRect); |
1528 { | 1626 } |
1529 _cursorBlinking = !_cursorBlinking; | 1627 |
1530 updateCursor(); | 1628 void |
1629 TerminalDisplay::blinkCursorEvent () | |
1630 { | |
1631 _cursorBlinking = !_cursorBlinking; | |
1632 updateCursor (); | |
1531 } | 1633 } |
1532 | 1634 |
1533 /* ------------------------------------------------------------------------- */ | 1635 /* ------------------------------------------------------------------------- */ |
1534 /* */ | 1636 /* */ |
1535 /* Resizing */ | 1637 /* Resizing */ |
1536 /* */ | 1638 /* */ |
1537 /* ------------------------------------------------------------------------- */ | 1639 /* ------------------------------------------------------------------------- */ |
1538 | 1640 |
1539 void TerminalDisplay::resizeEvent(QResizeEvent*) | 1641 void |
1540 { | 1642 TerminalDisplay::resizeEvent (QResizeEvent *) |
1541 updateImageSize(); | 1643 { |
1542 } | 1644 updateImageSize (); |
1543 | 1645 } |
1544 void TerminalDisplay::propagateSize() | 1646 |
1545 { | 1647 void |
1546 if (_isFixedSize) | 1648 TerminalDisplay::propagateSize () |
1547 { | 1649 { |
1548 setSize(_columns, _lines); | 1650 if (_isFixedSize) |
1549 QWidget::setFixedSize(sizeHint()); | 1651 { |
1550 parentWidget()->adjustSize(); | 1652 setSize (_columns, _lines); |
1551 parentWidget()->setFixedSize(parentWidget()->sizeHint()); | 1653 QWidget::setFixedSize (sizeHint ()); |
1552 return; | 1654 parentWidget ()->adjustSize (); |
1553 } | 1655 parentWidget ()->setFixedSize (parentWidget ()->sizeHint ()); |
1554 if (_image) | 1656 return; |
1555 updateImageSize(); | 1657 } |
1556 } | 1658 if (_image) |
1557 | 1659 updateImageSize (); |
1558 void TerminalDisplay::updateImageSize() | 1660 } |
1559 { | 1661 |
1560 Character* oldimg = _image; | 1662 void |
1561 int oldlin = _lines; | 1663 TerminalDisplay::updateImageSize () |
1562 int oldcol = _columns; | 1664 { |
1563 | 1665 Character *oldimg = _image; |
1564 makeImage(); | 1666 int oldlin = _lines; |
1565 | 1667 int oldcol = _columns; |
1566 // copy the old image to reduce flicker | 1668 |
1567 int lines = qMin(oldlin,_lines); | 1669 makeImage (); |
1568 int columns = qMin(oldcol,_columns); | 1670 |
1569 | 1671 // copy the old image to reduce flicker |
1570 if (oldimg) | 1672 int lines = qMin (oldlin, _lines); |
1571 { | 1673 int columns = qMin (oldcol, _columns); |
1572 for (int line = 0; line < lines; line++) | 1674 |
1573 { | 1675 if (oldimg) |
1574 memcpy((void*)&_image[_columns*line], | 1676 { |
1575 (void*)&oldimg[oldcol*line],columns*sizeof(Character)); | 1677 for (int line = 0; line < lines; line++) |
1576 } | 1678 { |
1577 delete[] oldimg; | 1679 memcpy ((void *) &_image[_columns * line], |
1578 } | 1680 (void *) &oldimg[oldcol * line], |
1579 | 1681 columns * sizeof (Character)); |
1580 if (_screenWindow) | 1682 } |
1581 _screenWindow->setWindowLines(_lines); | 1683 delete[]oldimg; |
1582 | 1684 } |
1583 _resizing = (oldlin!=_lines) || (oldcol!=_columns); | 1685 |
1584 | 1686 if (_screenWindow) |
1585 if ( _resizing ) | 1687 _screenWindow->setWindowLines (_lines); |
1586 { | 1688 |
1587 showResizeNotification(); | 1689 _resizing = (oldlin != _lines) || (oldcol != _columns); |
1588 emit changedContentSizeSignal(_contentHeight, _contentWidth); // expose resizeEvent | 1690 |
1589 } | 1691 if (_resizing) |
1590 | 1692 { |
1591 _resizing = false; | 1693 showResizeNotification (); |
1694 emit changedContentSizeSignal (_contentHeight, _contentWidth); // expose resizeEvent | |
1695 } | |
1696 | |
1697 _resizing = false; | |
1592 } | 1698 } |
1593 | 1699 |
1594 //showEvent and hideEvent are reimplemented here so that it appears to other classes that the | 1700 //showEvent and hideEvent are reimplemented here so that it appears to other classes that the |
1595 //display has been resized when the display is hidden or shown. | 1701 //display has been resized when the display is hidden or shown. |
1596 // | 1702 // |
1597 //TODO: Perhaps it would be better to have separate signals for show and hide instead of using | 1703 //TODO: Perhaps it would be better to have separate signals for show and hide instead of using |
1598 //the same signal as the one for a content size change | 1704 //the same signal as the one for a content size change |
1599 void TerminalDisplay::showEvent(QShowEvent*) | 1705 void |
1600 { | 1706 TerminalDisplay::showEvent (QShowEvent *) |
1601 emit changedContentSizeSignal(_contentHeight,_contentWidth); | 1707 { |
1602 } | 1708 emit changedContentSizeSignal (_contentHeight, _contentWidth); |
1603 void TerminalDisplay::hideEvent(QHideEvent*) | 1709 } |
1604 { | 1710 |
1605 emit changedContentSizeSignal(_contentHeight,_contentWidth); | 1711 void |
1712 TerminalDisplay::hideEvent (QHideEvent *) | |
1713 { | |
1714 emit changedContentSizeSignal (_contentHeight, _contentWidth); | |
1606 } | 1715 } |
1607 | 1716 |
1608 /* ------------------------------------------------------------------------- */ | 1717 /* ------------------------------------------------------------------------- */ |
1609 /* */ | 1718 /* */ |
1610 /* Scrollbar */ | 1719 /* Scrollbar */ |
1611 /* */ | 1720 /* */ |
1612 /* ------------------------------------------------------------------------- */ | 1721 /* ------------------------------------------------------------------------- */ |
1613 | 1722 |
1614 void TerminalDisplay::scrollBarPositionChanged(int) | 1723 void |
1615 { | 1724 TerminalDisplay::scrollBarPositionChanged (int) |
1616 if ( !_screenWindow ) | 1725 { |
1617 return; | 1726 if (!_screenWindow) |
1618 | 1727 return; |
1619 _screenWindow->scrollTo( _scrollBar->value() ); | 1728 |
1620 | 1729 _screenWindow->scrollTo (_scrollBar->value ()); |
1621 // if the thumb has been moved to the bottom of the _scrollBar then set | 1730 |
1622 // the display to automatically track new output, | 1731 // if the thumb has been moved to the bottom of the _scrollBar then set |
1623 // that is, scroll down automatically | 1732 // the display to automatically track new output, |
1624 // to how new _lines as they are added | 1733 // that is, scroll down automatically |
1625 const bool atEndOfOutput = (_scrollBar->value() == _scrollBar->maximum()); | 1734 // to how new _lines as they are added |
1626 _screenWindow->setTrackOutput( atEndOfOutput ); | 1735 const bool atEndOfOutput = (_scrollBar->value () == _scrollBar->maximum ()); |
1627 | 1736 _screenWindow->setTrackOutput (atEndOfOutput); |
1628 updateImage(); | 1737 |
1629 } | 1738 updateImage (); |
1630 | 1739 } |
1631 void TerminalDisplay::setScroll(int cursor, int slines) | 1740 |
1632 { | 1741 void |
1633 // update _scrollBar if the range or value has changed, | 1742 TerminalDisplay::setScroll (int cursor, int slines) |
1634 // otherwise return | 1743 { |
1635 // | 1744 // update _scrollBar if the range or value has changed, |
1636 // setting the range or value of a _scrollBar will always trigger | 1745 // otherwise return |
1637 // a repaint, so it should be avoided if it is not necessary | 1746 // |
1638 if ( _scrollBar->minimum() == 0 && | 1747 // setting the range or value of a _scrollBar will always trigger |
1639 _scrollBar->maximum() == (slines - _lines) && | 1748 // a repaint, so it should be avoided if it is not necessary |
1640 _scrollBar->value() == cursor ) | 1749 if (_scrollBar->minimum () == 0 && |
1641 { | 1750 _scrollBar->maximum () == (slines - _lines) && |
1642 return; | 1751 _scrollBar->value () == cursor) |
1643 } | 1752 { |
1644 | 1753 return; |
1645 disconnect(_scrollBar, SIGNAL(valueChanged(int)), this, SLOT(scrollBarPositionChanged(int))); | 1754 } |
1646 _scrollBar->setRange(0,slines - _lines); | 1755 |
1647 _scrollBar->setSingleStep(1); | 1756 disconnect (_scrollBar, SIGNAL (valueChanged (int)), this, |
1648 _scrollBar->setPageStep(_lines); | 1757 SLOT (scrollBarPositionChanged (int))); |
1649 _scrollBar->setValue(cursor); | 1758 _scrollBar->setRange (0, slines - _lines); |
1650 connect(_scrollBar, SIGNAL(valueChanged(int)), this, SLOT(scrollBarPositionChanged(int))); | 1759 _scrollBar->setSingleStep (1); |
1651 } | 1760 _scrollBar->setPageStep (_lines); |
1652 | 1761 _scrollBar->setValue (cursor); |
1653 void TerminalDisplay::setScrollBarPosition(ScrollBarPosition position) | 1762 connect (_scrollBar, SIGNAL (valueChanged (int)), this, |
1654 { | 1763 SLOT (scrollBarPositionChanged (int))); |
1655 if (_scrollbarLocation == position) | 1764 } |
1656 return; | 1765 |
1657 | 1766 void |
1658 if ( position == NoScrollBar ) | 1767 TerminalDisplay::setScrollBarPosition (ScrollBarPosition position) |
1659 _scrollBar->hide(); | 1768 { |
1660 else | 1769 if (_scrollbarLocation == position) |
1661 _scrollBar->show(); | 1770 return; |
1662 | 1771 |
1663 _topMargin = _leftMargin = 1; | 1772 if (position == NoScrollBar) |
1664 _scrollbarLocation = position; | 1773 _scrollBar->hide (); |
1665 | 1774 else |
1666 propagateSize(); | 1775 _scrollBar->show (); |
1667 update(); | 1776 |
1668 } | 1777 _topMargin = _leftMargin = 1; |
1669 | 1778 _scrollbarLocation = position; |
1670 void TerminalDisplay::mousePressEvent(QMouseEvent* ev) | 1779 |
1671 { | 1780 propagateSize (); |
1672 if ( _possibleTripleClick && (ev->button()==Qt::LeftButton) ) { | 1781 update (); |
1673 mouseTripleClickEvent(ev); | 1782 } |
1674 return; | 1783 |
1675 } | 1784 void |
1676 | 1785 TerminalDisplay::mousePressEvent (QMouseEvent * ev) |
1677 if ( !contentsRect().contains(ev->pos()) ) return; | 1786 { |
1678 | 1787 if (_possibleTripleClick && (ev->button () == Qt::LeftButton)) |
1679 if ( !_screenWindow ) return; | 1788 { |
1680 | 1789 mouseTripleClickEvent (ev); |
1681 int charLine; | 1790 return; |
1682 int charColumn; | 1791 } |
1683 getCharacterPosition(ev->pos(),charLine,charColumn); | 1792 |
1684 QPoint pos = QPoint(charColumn,charLine); | 1793 if (!contentsRect ().contains (ev->pos ())) |
1685 | 1794 return; |
1686 if ( ev->button() == Qt::LeftButton) | 1795 |
1687 { | 1796 if (!_screenWindow) |
1688 _lineSelectionMode = false; | 1797 return; |
1689 _wordSelectionMode = false; | 1798 |
1690 | 1799 int charLine; |
1691 emit isBusySelecting(true); // Keep it steady... | 1800 int charColumn; |
1692 // Drag only when the Control key is hold | 1801 getCharacterPosition (ev->pos (), charLine, charColumn); |
1693 bool selected = false; | 1802 QPoint pos = QPoint (charColumn, charLine); |
1694 | 1803 |
1695 // The receiver of the testIsSelected() signal will adjust | 1804 if (ev->button () == Qt::LeftButton) |
1696 // 'selected' accordingly. | 1805 { |
1697 //emit testIsSelected(pos.x(), pos.y(), selected); | 1806 _lineSelectionMode = false; |
1698 | 1807 _wordSelectionMode = false; |
1699 selected = _screenWindow->isSelected(pos.x(),pos.y()); | 1808 |
1700 | 1809 emit isBusySelecting (true); // Keep it steady... |
1701 if ((!_ctrlDrag || ev->modifiers() & Qt::ControlModifier) && selected ) { | 1810 // Drag only when the Control key is hold |
1702 // The user clicked inside selected text | 1811 bool selected = false; |
1703 dragInfo.state = diPending; | 1812 |
1704 dragInfo.start = ev->pos(); | 1813 // The receiver of the testIsSelected() signal will adjust |
1705 } | 1814 // 'selected' accordingly. |
1706 else { | 1815 //emit testIsSelected(pos.x(), pos.y(), selected); |
1707 // No reason to ever start a drag event | 1816 |
1708 dragInfo.state = diNone; | 1817 selected = _screenWindow->isSelected (pos.x (), pos.y ()); |
1709 | 1818 |
1710 _preserveLineBreaks = !( ( ev->modifiers() & Qt::ControlModifier ) && !(ev->modifiers() & Qt::AltModifier) ); | 1819 if ((!_ctrlDrag || ev->modifiers () & Qt::ControlModifier) && selected) |
1711 _columnSelectionMode = (ev->modifiers() & Qt::AltModifier) && (ev->modifiers() & Qt::ControlModifier); | 1820 { |
1712 | 1821 // The user clicked inside selected text |
1713 if (_mouseMarks || (ev->modifiers() & Qt::ShiftModifier)) | 1822 dragInfo.state = diPending; |
1714 { | 1823 dragInfo.start = ev->pos (); |
1715 _screenWindow->clearSelection(); | 1824 } |
1716 | 1825 else |
1717 //emit clearSelectionSignal(); | 1826 { |
1718 pos.ry() += _scrollBar->value(); | 1827 // No reason to ever start a drag event |
1719 _iPntSel = _pntSel = pos; | 1828 dragInfo.state = diNone; |
1720 _actSel = 1; // left mouse button pressed but nothing selected yet. | 1829 |
1721 | 1830 _preserveLineBreaks = !((ev->modifiers () & Qt::ControlModifier) |
1722 } | 1831 && !(ev->modifiers () & Qt::AltModifier)); |
1723 else | 1832 _columnSelectionMode = (ev->modifiers () & Qt::AltModifier) |
1724 { | 1833 && (ev->modifiers () & Qt::ControlModifier); |
1725 emit mouseSignal( 0, charColumn + 1, charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , 0); | 1834 |
1726 } | 1835 if (_mouseMarks || (ev->modifiers () & Qt::ShiftModifier)) |
1727 } | 1836 { |
1728 } | 1837 _screenWindow->clearSelection (); |
1729 else if ( ev->button() == Qt::MidButton ) | 1838 |
1730 { | 1839 //emit clearSelectionSignal(); |
1731 if ( _mouseMarks || (!_mouseMarks && (ev->modifiers() & Qt::ShiftModifier)) ) | 1840 pos.ry () += _scrollBar->value (); |
1732 emitSelection(true,ev->modifiers() & Qt::ControlModifier); | 1841 _iPntSel = _pntSel = pos; |
1733 else | 1842 _actSel = 1; // left mouse button pressed but nothing selected yet. |
1734 emit mouseSignal( 1, charColumn +1, charLine +1 +_scrollBar->value() -_scrollBar->maximum() , 0); | 1843 |
1735 } | 1844 } |
1736 else if ( ev->button() == Qt::RightButton ) | 1845 else |
1737 { | 1846 { |
1738 if (_mouseMarks || (ev->modifiers() & Qt::ShiftModifier)) | 1847 emit mouseSignal (0, charColumn + 1, |
1739 emit configureRequest(ev->pos()); | 1848 charLine + 1 + _scrollBar->value () - |
1740 else | 1849 _scrollBar->maximum (), 0); |
1741 emit mouseSignal( 2, charColumn +1, charLine +1 +_scrollBar->value() -_scrollBar->maximum() , 0); | 1850 } |
1742 } | 1851 } |
1743 } | 1852 } |
1744 | 1853 else if (ev->button () == Qt::MidButton) |
1745 QList<QAction*> TerminalDisplay::filterActions(const QPoint& position) | 1854 { |
1746 { | 1855 if (_mouseMarks |
1747 int charLine, charColumn; | 1856 || (!_mouseMarks && (ev->modifiers () & Qt::ShiftModifier))) |
1748 getCharacterPosition(position,charLine,charColumn); | 1857 emitSelection (true, ev->modifiers () & Qt::ControlModifier); |
1749 | 1858 else |
1750 Filter::HotSpot* spot = _filterChain->hotSpotAt(charLine,charColumn); | 1859 emit mouseSignal (1, charColumn + 1, |
1751 | 1860 charLine + 1 + _scrollBar->value () - |
1752 return spot ? spot->actions() : QList<QAction*>(); | 1861 _scrollBar->maximum (), 0); |
1753 } | 1862 } |
1754 | 1863 else if (ev->button () == Qt::RightButton) |
1755 void TerminalDisplay::mouseMoveEvent(QMouseEvent* ev) | 1864 { |
1756 { | 1865 if (_mouseMarks || (ev->modifiers () & Qt::ShiftModifier)) |
1757 int charLine = 0; | 1866 emit configureRequest (ev->pos ()); |
1758 int charColumn = 0; | 1867 else |
1759 int scrollBarWidth = (_scrollbarLocation == ScrollBarLeft) ? _scrollBar->width() : 0; | 1868 emit mouseSignal (2, charColumn + 1, |
1760 | 1869 charLine + 1 + _scrollBar->value () - |
1761 getCharacterPosition(ev->pos(),charLine,charColumn); | 1870 _scrollBar->maximum (), 0); |
1762 | 1871 } |
1763 // handle filters | 1872 } |
1764 // change link hot-spot appearance on mouse-over | 1873 |
1765 Filter::HotSpot* spot = _filterChain->hotSpotAt(charLine,charColumn); | 1874 QList < QAction * >TerminalDisplay::filterActions (const QPoint & position) |
1766 if ( spot && spot->type() == Filter::HotSpot::Link) | 1875 { |
1767 { | 1876 int |
1768 QRegion previousHotspotArea = _mouseOverHotspotArea; | 1877 charLine, |
1769 _mouseOverHotspotArea = QRegion(); | 1878 charColumn; |
1770 QRect r; | 1879 getCharacterPosition (position, charLine, charColumn); |
1771 if (spot->startLine()==spot->endLine()) { | 1880 |
1772 r.setCoords( spot->startColumn()*_fontWidth + scrollBarWidth, | 1881 Filter::HotSpot * spot = _filterChain->hotSpotAt (charLine, charColumn); |
1773 spot->startLine()*_fontHeight, | 1882 |
1774 spot->endColumn()*_fontWidth + scrollBarWidth, | 1883 return spot ? spot->actions () : QList < QAction * >(); |
1775 (spot->endLine()+1)*_fontHeight - 1 ); | 1884 } |
1776 _mouseOverHotspotArea |= r; | 1885 |
1777 } else { | 1886 void |
1778 r.setCoords( spot->startColumn()*_fontWidth + scrollBarWidth, | 1887 TerminalDisplay::mouseMoveEvent (QMouseEvent * ev) |
1779 spot->startLine()*_fontHeight, | 1888 { |
1780 _columns*_fontWidth - 1 + scrollBarWidth, | 1889 int charLine = 0; |
1781 (spot->startLine()+1)*_fontHeight ); | 1890 int charColumn = 0; |
1782 _mouseOverHotspotArea |= r; | 1891 int scrollBarWidth = |
1783 for ( int line = spot->startLine()+1 ; line < spot->endLine() ; line++ ) { | 1892 (_scrollbarLocation == ScrollBarLeft) ? _scrollBar->width () : 0; |
1784 r.setCoords( 0*_fontWidth + scrollBarWidth, | 1893 |
1785 line*_fontHeight, | 1894 getCharacterPosition (ev->pos (), charLine, charColumn); |
1786 _columns*_fontWidth + scrollBarWidth, | 1895 |
1787 (line+1)*_fontHeight ); | 1896 // handle filters |
1788 _mouseOverHotspotArea |= r; | 1897 // change link hot-spot appearance on mouse-over |
1789 } | 1898 Filter::HotSpot * spot = _filterChain->hotSpotAt (charLine, charColumn); |
1790 r.setCoords( 0*_fontWidth + scrollBarWidth, | 1899 if (spot && spot->type () == Filter::HotSpot::Link) |
1791 spot->endLine()*_fontHeight, | 1900 { |
1792 spot->endColumn()*_fontWidth + scrollBarWidth, | 1901 QRegion previousHotspotArea = _mouseOverHotspotArea; |
1793 (spot->endLine()+1)*_fontHeight ); | 1902 _mouseOverHotspotArea = QRegion (); |
1794 _mouseOverHotspotArea |= r; | 1903 QRect r; |
1795 } | 1904 if (spot->startLine () == spot->endLine ()) |
1796 // display tooltips when mousing over links | 1905 { |
1797 // TODO: Extend this to work with filter types other than links | 1906 r.setCoords (spot->startColumn () * _fontWidth + scrollBarWidth, |
1798 const QString& tooltip = spot->tooltip(); | 1907 spot->startLine () * _fontHeight, |
1799 if ( !tooltip.isEmpty() ) | 1908 spot->endColumn () * _fontWidth + scrollBarWidth, |
1800 { | 1909 (spot->endLine () + 1) * _fontHeight - 1); |
1801 QToolTip::showText( mapToGlobal(ev->pos()) , tooltip , this , _mouseOverHotspotArea.boundingRect() ); | 1910 _mouseOverHotspotArea |= r; |
1802 } | 1911 } |
1803 | 1912 else |
1804 update( _mouseOverHotspotArea | previousHotspotArea ); | 1913 { |
1805 } | 1914 r.setCoords (spot->startColumn () * _fontWidth + scrollBarWidth, |
1806 else if ( !_mouseOverHotspotArea.isEmpty() ) | 1915 spot->startLine () * _fontHeight, |
1807 { | 1916 _columns * _fontWidth - 1 + scrollBarWidth, |
1808 update( _mouseOverHotspotArea ); | 1917 (spot->startLine () + 1) * _fontHeight); |
1809 // set hotspot area to an invalid rectangle | 1918 _mouseOverHotspotArea |= r; |
1810 _mouseOverHotspotArea = QRegion(); | 1919 for (int line = spot->startLine () + 1; line < spot->endLine (); |
1811 } | 1920 line++) |
1812 | 1921 { |
1813 // for auto-hiding the cursor, we need mouseTracking | 1922 r.setCoords (0 * _fontWidth + scrollBarWidth, |
1814 if (ev->buttons() == Qt::NoButton ) return; | 1923 line * _fontHeight, |
1815 | 1924 _columns * _fontWidth + scrollBarWidth, |
1816 // if the terminal is interested in mouse movements | 1925 (line + 1) * _fontHeight); |
1817 // then emit a mouse movement signal, unless the shift | 1926 _mouseOverHotspotArea |= r; |
1818 // key is being held down, which overrides this. | 1927 } |
1819 if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier)) | 1928 r.setCoords (0 * _fontWidth + scrollBarWidth, |
1820 { | 1929 spot->endLine () * _fontHeight, |
1821 int button = 3; | 1930 spot->endColumn () * _fontWidth + scrollBarWidth, |
1822 if (ev->buttons() & Qt::LeftButton) | 1931 (spot->endLine () + 1) * _fontHeight); |
1823 button = 0; | 1932 _mouseOverHotspotArea |= r; |
1824 if (ev->buttons() & Qt::MidButton) | 1933 } |
1825 button = 1; | 1934 // display tooltips when mousing over links |
1826 if (ev->buttons() & Qt::RightButton) | 1935 // TODO: Extend this to work with filter types other than links |
1827 button = 2; | 1936 const QString & tooltip = spot->tooltip (); |
1828 | 1937 if (!tooltip.isEmpty ()) |
1829 | 1938 { |
1830 emit mouseSignal( button, | 1939 QToolTip::showText (mapToGlobal (ev->pos ()), tooltip, this, |
1831 charColumn + 1, | 1940 _mouseOverHotspotArea.boundingRect ()); |
1832 charLine + 1 +_scrollBar->value() -_scrollBar->maximum(), | 1941 } |
1833 1 ); | 1942 |
1834 | 1943 update (_mouseOverHotspotArea | previousHotspotArea); |
1835 return; | 1944 } |
1836 } | 1945 else if (!_mouseOverHotspotArea.isEmpty ()) |
1837 | 1946 { |
1838 if (dragInfo.state == diPending) | 1947 update (_mouseOverHotspotArea); |
1839 { | 1948 // set hotspot area to an invalid rectangle |
1840 // we had a mouse down, but haven't confirmed a drag yet | 1949 _mouseOverHotspotArea = QRegion (); |
1841 // if the mouse has moved sufficiently, we will confirm | 1950 } |
1842 | 1951 |
1843 int distance = 10; //KGlobalSettings::dndEventDelay(); | 1952 // for auto-hiding the cursor, we need mouseTracking |
1844 if ( ev->x() > dragInfo.start.x() + distance || ev->x() < dragInfo.start.x() - distance || | 1953 if (ev->buttons () == Qt::NoButton) |
1845 ev->y() > dragInfo.start.y() + distance || ev->y() < dragInfo.start.y() - distance) | 1954 return; |
1846 { | 1955 |
1847 // we've left the drag square, we can start a real drag operation now | 1956 // if the terminal is interested in mouse movements |
1848 emit isBusySelecting(false); // Ok.. we can breath again. | 1957 // then emit a mouse movement signal, unless the shift |
1849 | 1958 // key is being held down, which overrides this. |
1850 _screenWindow->clearSelection(); | 1959 if (!_mouseMarks && !(ev->modifiers () & Qt::ShiftModifier)) |
1851 doDrag(); | 1960 { |
1852 } | 1961 int button = 3; |
1853 return; | 1962 if (ev->buttons () & Qt::LeftButton) |
1854 } | 1963 button = 0; |
1855 else if (dragInfo.state == diDragging) | 1964 if (ev->buttons () & Qt::MidButton) |
1856 { | 1965 button = 1; |
1857 // this isn't technically needed because mouseMoveEvent is suppressed during | 1966 if (ev->buttons () & Qt::RightButton) |
1858 // Qt drag operations, replaced by dragMoveEvent | 1967 button = 2; |
1859 return; | 1968 |
1860 } | 1969 |
1861 | 1970 emit mouseSignal (button, |
1862 if (_actSel == 0) return; | 1971 charColumn + 1, |
1863 | 1972 charLine + 1 + _scrollBar->value () - |
1864 // don't extend selection while pasting | 1973 _scrollBar->maximum (), 1); |
1865 if (ev->buttons() & Qt::MidButton) return; | 1974 |
1866 | 1975 return; |
1867 extendSelection( ev->pos() ); | 1976 } |
1868 } | 1977 |
1869 | 1978 if (dragInfo.state == diPending) |
1870 void TerminalDisplay::extendSelection( const QPoint& position ) | 1979 { |
1871 { | 1980 // we had a mouse down, but haven't confirmed a drag yet |
1872 QPoint pos = position; | 1981 // if the mouse has moved sufficiently, we will confirm |
1873 | 1982 |
1874 if ( !_screenWindow ) | 1983 int distance = 10; //KGlobalSettings::dndEventDelay(); |
1875 return; | 1984 if (ev->x () > dragInfo.start.x () + distance |
1876 | 1985 || ev->x () < dragInfo.start.x () - distance |
1877 //if ( !contentsRect().contains(ev->pos()) ) return; | 1986 || ev->y () > dragInfo.start.y () + distance |
1878 QPoint tL = contentsRect().topLeft(); | 1987 || ev->y () < dragInfo.start.y () - distance) |
1879 int tLx = tL.x(); | 1988 { |
1880 int tLy = tL.y(); | 1989 // we've left the drag square, we can start a real drag operation now |
1881 int scroll = _scrollBar->value(); | 1990 emit isBusySelecting (false); // Ok.. we can breath again. |
1882 | 1991 |
1883 // we're in the process of moving the mouse with the left button pressed | 1992 _screenWindow->clearSelection (); |
1884 // the mouse cursor will kept caught within the bounds of the text in | 1993 doDrag (); |
1885 // this widget. | 1994 } |
1886 | 1995 return; |
1887 int linesBeyondWidget = 0; | 1996 } |
1888 | 1997 else if (dragInfo.state == diDragging) |
1889 QRect textBounds(tLx + _leftMargin, | 1998 { |
1890 tLy + _topMargin, | 1999 // this isn't technically needed because mouseMoveEvent is suppressed during |
1891 _usedColumns*_fontWidth-1, | 2000 // Qt drag operations, replaced by dragMoveEvent |
1892 _usedLines*_fontHeight-1); | 2001 return; |
1893 | 2002 } |
1894 // Adjust position within text area bounds. | 2003 |
1895 QPoint oldpos = pos; | 2004 if (_actSel == 0) |
1896 | 2005 return; |
1897 pos.setX( qBound(textBounds.left(),pos.x(),textBounds.right()) ); | 2006 |
1898 pos.setY( qBound(textBounds.top(),pos.y(),textBounds.bottom()) ); | 2007 // don't extend selection while pasting |
1899 | 2008 if (ev->buttons () & Qt::MidButton) |
1900 if ( oldpos.y() > textBounds.bottom() ) | 2009 return; |
1901 { | 2010 |
1902 linesBeyondWidget = (oldpos.y()-textBounds.bottom()) / _fontHeight; | 2011 extendSelection (ev->pos ()); |
1903 _scrollBar->setValue(_scrollBar->value()+linesBeyondWidget+1); // scrollforward | 2012 } |
1904 } | 2013 |
1905 if ( oldpos.y() < textBounds.top() ) | 2014 void |
1906 { | 2015 TerminalDisplay::extendSelection (const QPoint & position) |
1907 linesBeyondWidget = (textBounds.top()-oldpos.y()) / _fontHeight; | 2016 { |
1908 _scrollBar->setValue(_scrollBar->value()-linesBeyondWidget-1); // history | 2017 QPoint pos = position; |
1909 } | 2018 |
1910 | 2019 if (!_screenWindow) |
1911 int charColumn = 0; | 2020 return; |
1912 int charLine = 0; | 2021 |
1913 getCharacterPosition(pos,charLine,charColumn); | 2022 //if ( !contentsRect().contains(ev->pos()) ) return; |
1914 | 2023 QPoint tL = contentsRect ().topLeft (); |
1915 QPoint here = QPoint(charColumn,charLine); //QPoint((pos.x()-tLx-_leftMargin+(_fontWidth/2))/_fontWidth,(pos.y()-tLy-_topMargin)/_fontHeight); | 2024 int tLx = tL.x (); |
1916 QPoint ohere; | 2025 int tLy = tL.y (); |
1917 QPoint _iPntSelCorr = _iPntSel; | 2026 int scroll = _scrollBar->value (); |
1918 _iPntSelCorr.ry() -= _scrollBar->value(); | 2027 |
1919 QPoint _pntSelCorr = _pntSel; | 2028 // we're in the process of moving the mouse with the left button pressed |
1920 _pntSelCorr.ry() -= _scrollBar->value(); | 2029 // the mouse cursor will kept caught within the bounds of the text in |
1921 bool swapping = false; | 2030 // this widget. |
1922 | 2031 |
1923 if ( _wordSelectionMode ) | 2032 int linesBeyondWidget = 0; |
1924 { | 2033 |
1925 // Extend to word boundaries | 2034 QRect textBounds (tLx + _leftMargin, |
1926 int i; | 2035 tLy + _topMargin, |
1927 QChar selClass; | 2036 _usedColumns * _fontWidth - 1, |
1928 | 2037 _usedLines * _fontHeight - 1); |
1929 bool left_not_right = ( here.y() < _iPntSelCorr.y() || | 2038 |
1930 ( here.y() == _iPntSelCorr.y() && here.x() < _iPntSelCorr.x() ) ); | 2039 // Adjust position within text area bounds. |
1931 bool old_left_not_right = ( _pntSelCorr.y() < _iPntSelCorr.y() || | 2040 QPoint oldpos = pos; |
1932 ( _pntSelCorr.y() == _iPntSelCorr.y() && _pntSelCorr.x() < _iPntSelCorr.x() ) ); | 2041 |
1933 swapping = left_not_right != old_left_not_right; | 2042 pos.setX (qBound (textBounds.left (), pos.x (), textBounds.right ())); |
1934 | 2043 pos.setY (qBound (textBounds.top (), pos.y (), textBounds.bottom ())); |
1935 // Find left (left_not_right ? from here : from start) | 2044 |
1936 QPoint left = left_not_right ? here : _iPntSelCorr; | 2045 if (oldpos.y () > textBounds.bottom ()) |
1937 i = loc(left.x(),left.y()); | 2046 { |
1938 if (i>=0 && i<=_imageSize) { | 2047 linesBeyondWidget = (oldpos.y () - textBounds.bottom ()) / _fontHeight; |
1939 selClass = charClass(_image[i].character); | 2048 _scrollBar->setValue (_scrollBar->value () + linesBeyondWidget + 1); // scrollforward |
1940 while ( ((left.x()>0) || (left.y()>0 && (_lineProperties[left.y()-1] & LINE_WRAPPED) )) | 2049 } |
1941 && charClass(_image[i-1].character) == selClass ) | 2050 if (oldpos.y () < textBounds.top ()) |
1942 { i--; if (left.x()>0) left.rx()--; else {left.rx()=_usedColumns-1; left.ry()--;} } | 2051 { |
1943 } | 2052 linesBeyondWidget = (textBounds.top () - oldpos.y ()) / _fontHeight; |
1944 | 2053 _scrollBar->setValue (_scrollBar->value () - linesBeyondWidget - 1); // history |
1945 // Find left (left_not_right ? from start : from here) | 2054 } |
1946 QPoint right = left_not_right ? _iPntSelCorr : here; | 2055 |
1947 i = loc(right.x(),right.y()); | 2056 int charColumn = 0; |
1948 if (i>=0 && i<=_imageSize) { | 2057 int charLine = 0; |
1949 selClass = charClass(_image[i].character); | 2058 getCharacterPosition (pos, charLine, charColumn); |
1950 while( ((right.x()<_usedColumns-1) || (right.y()<_usedLines-1 && (_lineProperties[right.y()] & LINE_WRAPPED) )) | 2059 |
1951 && charClass(_image[i+1].character) == selClass ) | 2060 QPoint here = QPoint (charColumn, charLine); //QPoint((pos.x()-tLx-_leftMargin+(_fontWidth/2))/_fontWidth,(pos.y()-tLy-_topMargin)/_fontHeight); |
1952 { i++; if (right.x()<_usedColumns-1) right.rx()++; else {right.rx()=0; right.ry()++; } } | 2061 QPoint ohere; |
1953 } | 2062 QPoint _iPntSelCorr = _iPntSel; |
1954 | 2063 _iPntSelCorr.ry () -= _scrollBar->value (); |
1955 // Pick which is start (ohere) and which is extension (here) | 2064 QPoint _pntSelCorr = _pntSel; |
1956 if ( left_not_right ) | 2065 _pntSelCorr.ry () -= _scrollBar->value (); |
1957 { | 2066 bool swapping = false; |
1958 here = left; ohere = right; | 2067 |
1959 } | 2068 if (_wordSelectionMode) |
1960 else | 2069 { |
1961 { | 2070 // Extend to word boundaries |
1962 here = right; ohere = left; | 2071 int i; |
1963 } | 2072 QChar selClass; |
1964 ohere.rx()++; | 2073 |
1965 } | 2074 bool left_not_right = (here.y () < _iPntSelCorr.y () || |
1966 | 2075 (here.y () == _iPntSelCorr.y () |
1967 if ( _lineSelectionMode ) | 2076 && here.x () < _iPntSelCorr.x ())); |
1968 { | 2077 bool old_left_not_right = (_pntSelCorr.y () < _iPntSelCorr.y () |
1969 // Extend to complete line | 2078 || (_pntSelCorr.y () == _iPntSelCorr.y () |
1970 bool above_not_below = ( here.y() < _iPntSelCorr.y() ); | 2079 && _pntSelCorr.x () < |
1971 | 2080 _iPntSelCorr.x ())); |
1972 QPoint above = above_not_below ? here : _iPntSelCorr; | 2081 swapping = left_not_right != old_left_not_right; |
1973 QPoint below = above_not_below ? _iPntSelCorr : here; | 2082 |
1974 | 2083 // Find left (left_not_right ? from here : from start) |
1975 while (above.y()>0 && (_lineProperties[above.y()-1] & LINE_WRAPPED) ) | 2084 QPoint left = left_not_right ? here : _iPntSelCorr; |
1976 above.ry()--; | 2085 i = loc (left.x (), left.y ()); |
1977 while (below.y()<_usedLines-1 && (_lineProperties[below.y()] & LINE_WRAPPED) ) | 2086 if (i >= 0 && i <= _imageSize) |
1978 below.ry()++; | 2087 { |
1979 | 2088 selClass = charClass (_image[i].character); |
1980 above.setX(0); | 2089 while (((left.x () > 0) |
1981 below.setX(_usedColumns-1); | 2090 || (left.y () > 0 |
1982 | 2091 && (_lineProperties[left.y () - 1] & LINE_WRAPPED))) |
1983 // Pick which is start (ohere) and which is extension (here) | 2092 && charClass (_image[i - 1].character) == selClass) |
1984 if ( above_not_below ) | 2093 { |
1985 { | 2094 i--; |
1986 here = above; ohere = below; | 2095 if (left.x () > 0) |
1987 } | 2096 left.rx ()--; |
1988 else | 2097 else |
1989 { | 2098 { |
1990 here = below; ohere = above; | 2099 left.rx () = _usedColumns - 1; |
1991 } | 2100 left.ry ()--; |
1992 | 2101 } |
1993 QPoint newSelBegin = QPoint( ohere.x(), ohere.y() ); | 2102 } |
1994 swapping = !(_tripleSelBegin==newSelBegin); | 2103 } |
1995 _tripleSelBegin = newSelBegin; | 2104 |
1996 | 2105 // Find left (left_not_right ? from start : from here) |
1997 ohere.rx()++; | 2106 QPoint right = left_not_right ? _iPntSelCorr : here; |
1998 } | 2107 i = loc (right.x (), right.y ()); |
1999 | 2108 if (i >= 0 && i <= _imageSize) |
2000 int offset = 0; | 2109 { |
2001 if ( !_wordSelectionMode && !_lineSelectionMode ) | 2110 selClass = charClass (_image[i].character); |
2002 { | 2111 while (((right.x () < _usedColumns - 1) |
2003 int i; | 2112 || (right.y () < _usedLines - 1 |
2004 QChar selClass; | 2113 && (_lineProperties[right.y ()] & LINE_WRAPPED))) |
2005 | 2114 && charClass (_image[i + 1].character) == selClass) |
2006 bool left_not_right = ( here.y() < _iPntSelCorr.y() || | 2115 { |
2007 ( here.y() == _iPntSelCorr.y() && here.x() < _iPntSelCorr.x() ) ); | 2116 i++; |
2008 bool old_left_not_right = ( _pntSelCorr.y() < _iPntSelCorr.y() || | 2117 if (right.x () < _usedColumns - 1) |
2009 ( _pntSelCorr.y() == _iPntSelCorr.y() && _pntSelCorr.x() < _iPntSelCorr.x() ) ); | 2118 right.rx ()++; |
2010 swapping = left_not_right != old_left_not_right; | 2119 else |
2011 | 2120 { |
2012 // Find left (left_not_right ? from here : from start) | 2121 right.rx () = 0; |
2013 QPoint left = left_not_right ? here : _iPntSelCorr; | 2122 right.ry ()++; |
2014 | 2123 } |
2015 // Find left (left_not_right ? from start : from here) | 2124 } |
2016 QPoint right = left_not_right ? _iPntSelCorr : here; | 2125 } |
2017 if ( right.x() > 0 && !_columnSelectionMode ) | 2126 |
2018 { | 2127 // Pick which is start (ohere) and which is extension (here) |
2019 i = loc(right.x(),right.y()); | 2128 if (left_not_right) |
2020 if (i>=0 && i<=_imageSize) { | 2129 { |
2021 selClass = charClass(_image[i-1].character); | 2130 here = left; |
2022 /* if (selClass == ' ') | 2131 ohere = right; |
2023 { | 2132 } |
2024 while ( right.x() < _usedColumns-1 && charClass(_image[i+1].character) == selClass && (right.y()<_usedLines-1) && | 2133 else |
2025 !(_lineProperties[right.y()] & LINE_WRAPPED)) | 2134 { |
2026 { i++; right.rx()++; } | 2135 here = right; |
2027 if (right.x() < _usedColumns-1) | 2136 ohere = left; |
2028 right = left_not_right ? _iPntSelCorr : here; | 2137 } |
2029 else | 2138 ohere.rx ()++; |
2030 right.rx()++; // will be balanced later because of offset=-1; | 2139 } |
2031 }*/ | 2140 |
2032 } | 2141 if (_lineSelectionMode) |
2033 } | 2142 { |
2034 | 2143 // Extend to complete line |
2035 // Pick which is start (ohere) and which is extension (here) | 2144 bool above_not_below = (here.y () < _iPntSelCorr.y ()); |
2036 if ( left_not_right ) | 2145 |
2037 { | 2146 QPoint above = above_not_below ? here : _iPntSelCorr; |
2038 here = left; ohere = right; offset = 0; | 2147 QPoint below = above_not_below ? _iPntSelCorr : here; |
2039 } | 2148 |
2040 else | 2149 while (above.y () > 0 |
2041 { | 2150 && (_lineProperties[above.y () - 1] & LINE_WRAPPED)) |
2042 here = right; ohere = left; offset = -1; | 2151 above.ry ()--; |
2043 } | 2152 while (below.y () < _usedLines - 1 |
2044 } | 2153 && (_lineProperties[below.y ()] & LINE_WRAPPED)) |
2045 | 2154 below.ry ()++; |
2046 if ((here == _pntSelCorr) && (scroll == _scrollBar->value())) return; // not moved | 2155 |
2047 | 2156 above.setX (0); |
2048 if (here == ohere) return; // It's not left, it's not right. | 2157 below.setX (_usedColumns - 1); |
2049 | 2158 |
2050 if ( _actSel < 2 || swapping ) | 2159 // Pick which is start (ohere) and which is extension (here) |
2051 { | 2160 if (above_not_below) |
2052 if ( _columnSelectionMode && !_lineSelectionMode && !_wordSelectionMode ) | 2161 { |
2053 { | 2162 here = above; |
2054 _screenWindow->setSelectionStart( ohere.x() , ohere.y() , true ); | 2163 ohere = below; |
2055 } | 2164 } |
2056 else | 2165 else |
2057 { | 2166 { |
2058 _screenWindow->setSelectionStart( ohere.x()-1-offset , ohere.y() , false ); | 2167 here = below; |
2059 } | 2168 ohere = above; |
2060 | 2169 } |
2061 } | 2170 |
2062 | 2171 QPoint newSelBegin = QPoint (ohere.x (), ohere.y ()); |
2063 _actSel = 2; // within selection | 2172 swapping = !(_tripleSelBegin == newSelBegin); |
2064 _pntSel = here; | 2173 _tripleSelBegin = newSelBegin; |
2065 _pntSel.ry() += _scrollBar->value(); | 2174 |
2066 | 2175 ohere.rx ()++; |
2067 if ( _columnSelectionMode && !_lineSelectionMode && !_wordSelectionMode ) | 2176 } |
2068 { | 2177 |
2069 _screenWindow->setSelectionEnd( here.x() , here.y() ); | 2178 int offset = 0; |
2070 } | 2179 if (!_wordSelectionMode && !_lineSelectionMode) |
2071 else | 2180 { |
2072 { | 2181 int i; |
2073 _screenWindow->setSelectionEnd( here.x()+offset , here.y() ); | 2182 QChar selClass; |
2074 } | 2183 |
2075 | 2184 bool left_not_right = (here.y () < _iPntSelCorr.y () || |
2076 } | 2185 (here.y () == _iPntSelCorr.y () |
2077 | 2186 && here.x () < _iPntSelCorr.x ())); |
2078 void TerminalDisplay::mouseReleaseEvent(QMouseEvent* ev) | 2187 bool old_left_not_right = (_pntSelCorr.y () < _iPntSelCorr.y () |
2079 { | 2188 || (_pntSelCorr.y () == _iPntSelCorr.y () |
2080 if ( !_screenWindow ) | 2189 && _pntSelCorr.x () < |
2081 return; | 2190 _iPntSelCorr.x ())); |
2082 | 2191 swapping = left_not_right != old_left_not_right; |
2083 int charLine; | 2192 |
2084 int charColumn; | 2193 // Find left (left_not_right ? from here : from start) |
2085 getCharacterPosition(ev->pos(),charLine,charColumn); | 2194 QPoint left = left_not_right ? here : _iPntSelCorr; |
2086 | 2195 |
2087 if ( ev->button() == Qt::LeftButton) | 2196 // Find left (left_not_right ? from start : from here) |
2088 { | 2197 QPoint right = left_not_right ? _iPntSelCorr : here; |
2089 emit isBusySelecting(false); | 2198 if (right.x () > 0 && !_columnSelectionMode) |
2090 if(dragInfo.state == diPending) | 2199 { |
2091 { | 2200 i = loc (right.x (), right.y ()); |
2092 // We had a drag event pending but never confirmed. Kill selection | 2201 if (i >= 0 && i <= _imageSize) |
2093 _screenWindow->clearSelection(); | 2202 { |
2094 //emit clearSelectionSignal(); | 2203 selClass = charClass (_image[i - 1].character); |
2095 } | 2204 /* if (selClass == ' ') |
2096 else | 2205 { |
2097 { | 2206 while ( right.x() < _usedColumns-1 && charClass(_image[i+1].character) == selClass && (right.y()<_usedLines-1) && |
2098 if ( _actSel > 1 ) | 2207 !(_lineProperties[right.y()] & LINE_WRAPPED)) |
2099 { | 2208 { i++; right.rx()++; } |
2100 setSelection( _screenWindow->selectedText(_preserveLineBreaks) ); | 2209 if (right.x() < _usedColumns-1) |
2101 } | 2210 right = left_not_right ? _iPntSelCorr : here; |
2102 | 2211 else |
2103 _actSel = 0; | 2212 right.rx()++; // will be balanced later because of offset=-1; |
2104 | 2213 } */ |
2105 //FIXME: emits a release event even if the mouse is | 2214 } |
2106 // outside the range. The procedure used in `mouseMoveEvent' | 2215 } |
2107 // applies here, too. | 2216 |
2108 | 2217 // Pick which is start (ohere) and which is extension (here) |
2109 if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier)) | 2218 if (left_not_right) |
2110 emit mouseSignal( 3, // release | 2219 { |
2111 charColumn + 1, | 2220 here = left; |
2112 charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , 0); | 2221 ohere = right; |
2113 } | 2222 offset = 0; |
2114 dragInfo.state = diNone; | 2223 } |
2115 } | 2224 else |
2116 | 2225 { |
2117 | 2226 here = right; |
2118 if ( !_mouseMarks && | 2227 ohere = left; |
2119 ((ev->button() == Qt::RightButton && !(ev->modifiers() & Qt::ShiftModifier)) | 2228 offset = -1; |
2120 || ev->button() == Qt::MidButton) ) | 2229 } |
2121 { | 2230 } |
2122 emit mouseSignal( 3, | 2231 |
2123 charColumn + 1, | 2232 if ((here == _pntSelCorr) && (scroll == _scrollBar->value ())) |
2124 charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , | 2233 return; // not moved |
2125 0); | 2234 |
2126 } | 2235 if (here == ohere) |
2127 } | 2236 return; // It's not left, it's not right. |
2128 | 2237 |
2129 void TerminalDisplay::getCharacterPosition(const QPoint& widgetPoint,int& line,int& column) const | 2238 if (_actSel < 2 || swapping) |
2130 { | 2239 { |
2131 column = (widgetPoint.x() + _fontWidth/2 -contentsRect().left()-_leftMargin) / _fontWidth; | 2240 if (_columnSelectionMode && !_lineSelectionMode && !_wordSelectionMode) |
2132 line = (widgetPoint.y()-contentsRect().top()-_topMargin) / _fontHeight; | 2241 { |
2133 | 2242 _screenWindow->setSelectionStart (ohere.x (), ohere.y (), true); |
2134 if ( line < 0 ) | 2243 } |
2135 line = 0; | 2244 else |
2136 if ( column < 0 ) | 2245 { |
2137 column = 0; | 2246 _screenWindow->setSelectionStart (ohere.x () - 1 - offset, |
2138 | 2247 ohere.y (), false); |
2139 if ( line >= _usedLines ) | 2248 } |
2140 line = _usedLines-1; | 2249 |
2141 | 2250 } |
2142 // the column value returned can be equal to _usedColumns, which | 2251 |
2143 // is the position just after the last character displayed in a line. | 2252 _actSel = 2; // within selection |
2144 // | 2253 _pntSel = here; |
2145 // this is required so that the user can select characters in the right-most | 2254 _pntSel.ry () += _scrollBar->value (); |
2146 // column (or left-most for right-to-left input) | 2255 |
2147 if ( column > _usedColumns ) | 2256 if (_columnSelectionMode && !_lineSelectionMode && !_wordSelectionMode) |
2148 column = _usedColumns; | 2257 { |
2149 } | 2258 _screenWindow->setSelectionEnd (here.x (), here.y ()); |
2150 | 2259 } |
2151 void TerminalDisplay::updateLineProperties() | 2260 else |
2152 { | 2261 { |
2153 if ( !_screenWindow ) | 2262 _screenWindow->setSelectionEnd (here.x () + offset, here.y ()); |
2154 return; | 2263 } |
2155 | 2264 |
2156 _lineProperties = _screenWindow->getLineProperties(); | 2265 } |
2157 } | 2266 |
2158 | 2267 void |
2159 void TerminalDisplay::mouseDoubleClickEvent(QMouseEvent* ev) | 2268 TerminalDisplay::mouseReleaseEvent (QMouseEvent * ev) |
2160 { | 2269 { |
2161 if ( ev->button() != Qt::LeftButton) return; | 2270 if (!_screenWindow) |
2162 if ( !_screenWindow ) return; | 2271 return; |
2163 | 2272 |
2164 int charLine = 0; | 2273 int charLine; |
2165 int charColumn = 0; | 2274 int charColumn; |
2166 | 2275 getCharacterPosition (ev->pos (), charLine, charColumn); |
2167 getCharacterPosition(ev->pos(),charLine,charColumn); | 2276 |
2168 | 2277 if (ev->button () == Qt::LeftButton) |
2169 QPoint pos(charColumn,charLine); | 2278 { |
2170 | 2279 emit isBusySelecting (false); |
2171 // pass on double click as two clicks. | 2280 if (dragInfo.state == diPending) |
2172 if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier)) | 2281 { |
2173 { | 2282 // We had a drag event pending but never confirmed. Kill selection |
2174 // Send just _ONE_ click event, since the first click of the double click | 2283 _screenWindow->clearSelection (); |
2175 // was already sent by the click handler | 2284 //emit clearSelectionSignal(); |
2176 emit mouseSignal( 0, | 2285 } |
2177 pos.x()+1, | 2286 else |
2178 pos.y()+1 +_scrollBar->value() -_scrollBar->maximum(), | 2287 { |
2179 0 ); // left button | 2288 if (_actSel > 1) |
2180 return; | 2289 { |
2181 } | 2290 setSelection (_screenWindow-> |
2182 | 2291 selectedText (_preserveLineBreaks)); |
2183 _screenWindow->clearSelection(); | 2292 } |
2184 QPoint bgnSel = pos; | 2293 |
2185 QPoint endSel = pos; | 2294 _actSel = 0; |
2186 int i = loc(bgnSel.x(),bgnSel.y()); | 2295 |
2187 _iPntSel = bgnSel; | 2296 //FIXME: emits a release event even if the mouse is |
2188 _iPntSel.ry() += _scrollBar->value(); | 2297 // outside the range. The procedure used in `mouseMoveEvent' |
2189 | 2298 // applies here, too. |
2190 _wordSelectionMode = true; | 2299 |
2191 | 2300 if (!_mouseMarks && !(ev->modifiers () & Qt::ShiftModifier)) |
2192 // find word boundaries... | 2301 emit mouseSignal (3, // release |
2193 QChar selClass = charClass(_image[i].character); | 2302 charColumn + 1, |
2194 { | 2303 charLine + 1 + _scrollBar->value () - |
2195 // find the start of the word | 2304 _scrollBar->maximum (), 0); |
2196 int x = bgnSel.x(); | 2305 } |
2197 while ( ((x>0) || (bgnSel.y()>0 && (_lineProperties[bgnSel.y()-1] & LINE_WRAPPED) )) | 2306 dragInfo.state = diNone; |
2198 && charClass(_image[i-1].character) == selClass ) | 2307 } |
2199 { | 2308 |
2200 i--; | 2309 |
2201 if (x>0) | 2310 if (!_mouseMarks && |
2202 x--; | 2311 ((ev->button () == Qt::RightButton |
2203 else | 2312 && !(ev->modifiers () & Qt::ShiftModifier)) |
2204 { | 2313 || ev->button () == Qt::MidButton)) |
2205 x=_usedColumns-1; | 2314 { |
2206 bgnSel.ry()--; | 2315 emit mouseSignal (3, |
2207 } | 2316 charColumn + 1, |
2208 } | 2317 charLine + 1 + _scrollBar->value () - |
2209 | 2318 _scrollBar->maximum (), 0); |
2210 bgnSel.setX(x); | 2319 } |
2211 _screenWindow->setSelectionStart( bgnSel.x() , bgnSel.y() , false ); | 2320 } |
2212 | 2321 |
2213 // find the end of the word | 2322 void |
2214 i = loc( endSel.x(), endSel.y() ); | 2323 TerminalDisplay::getCharacterPosition (const QPoint & widgetPoint, int &line, |
2215 x = endSel.x(); | 2324 int &column) const |
2216 while( ((x<_usedColumns-1) || (endSel.y()<_usedLines-1 && (_lineProperties[endSel.y()] & LINE_WRAPPED) )) | 2325 { |
2217 && charClass(_image[i+1].character) == selClass ) | 2326 column = |
2218 { | 2327 (widgetPoint.x () + _fontWidth / 2 - contentsRect ().left () - |
2219 i++; | 2328 _leftMargin) / _fontWidth; |
2220 if (x<_usedColumns-1) | 2329 line = |
2221 x++; | 2330 (widgetPoint.y () - contentsRect ().top () - _topMargin) / _fontHeight; |
2222 else | 2331 |
2223 { | 2332 if (line < 0) |
2224 x=0; | 2333 line = 0; |
2225 endSel.ry()++; | 2334 if (column < 0) |
2226 } | 2335 column = 0; |
2227 } | 2336 |
2228 | 2337 if (line >= _usedLines) |
2229 endSel.setX(x); | 2338 line = _usedLines - 1; |
2230 | 2339 |
2231 // In word selection mode don't select @ (64) if at end of word. | 2340 // the column value returned can be equal to _usedColumns, which |
2232 if ( ( QChar( _image[i].character ) == '@' ) && ( ( endSel.x() - bgnSel.x() ) > 0 ) ) | 2341 // is the position just after the last character displayed in a line. |
2233 endSel.setX( x - 1 ); | 2342 // |
2234 | 2343 // this is required so that the user can select characters in the right-most |
2235 | 2344 // column (or left-most for right-to-left input) |
2236 _actSel = 2; // within selection | 2345 if (column > _usedColumns) |
2237 | 2346 column = _usedColumns; |
2238 _screenWindow->setSelectionEnd( endSel.x() , endSel.y() ); | 2347 } |
2239 | 2348 |
2240 setSelection( _screenWindow->selectedText(_preserveLineBreaks) ); | 2349 void |
2241 } | 2350 TerminalDisplay::updateLineProperties () |
2242 | 2351 { |
2243 _possibleTripleClick=true; | 2352 if (!_screenWindow) |
2244 | 2353 return; |
2245 QTimer::singleShot(QApplication::doubleClickInterval(),this, | 2354 |
2246 SLOT(tripleClickTimeout())); | 2355 _lineProperties = _screenWindow->getLineProperties (); |
2247 } | 2356 } |
2248 | 2357 |
2249 void TerminalDisplay::wheelEvent( QWheelEvent* ev ) | 2358 void |
2250 { | 2359 TerminalDisplay::mouseDoubleClickEvent (QMouseEvent * ev) |
2251 if (ev->orientation() != Qt::Vertical) | 2360 { |
2252 return; | 2361 if (ev->button () != Qt::LeftButton) |
2253 | 2362 return; |
2254 // if the terminal program is not interested mouse events | 2363 if (!_screenWindow) |
2255 // then send the event to the scrollbar if the slider has room to move | 2364 return; |
2256 // or otherwise send simulated up / down key presses to the terminal program | 2365 |
2257 // for the benefit of programs such as 'less' | 2366 int charLine = 0; |
2258 if ( _mouseMarks ) | 2367 int charColumn = 0; |
2259 { | 2368 |
2260 bool canScroll = _scrollBar->maximum() > 0; | 2369 getCharacterPosition (ev->pos (), charLine, charColumn); |
2261 if (canScroll) | 2370 |
2262 _scrollBar->event(ev); | 2371 QPoint pos (charColumn, charLine); |
2263 else | 2372 |
2264 { | 2373 // pass on double click as two clicks. |
2265 // assume that each Up / Down key event will cause the terminal application | 2374 if (!_mouseMarks && !(ev->modifiers () & Qt::ShiftModifier)) |
2266 // to scroll by one line. | 2375 { |
2267 // | 2376 // Send just _ONE_ click event, since the first click of the double click |
2268 // to get a reasonable scrolling speed, scroll by one line for every 5 degrees | 2377 // was already sent by the click handler |
2269 // of mouse wheel rotation. Mouse wheels typically move in steps of 15 degrees, | 2378 emit mouseSignal (0, pos.x () + 1, pos.y () + 1 + _scrollBar->value () - _scrollBar->maximum (), 0); // left button |
2270 // giving a scroll of 3 lines | 2379 return; |
2271 int key = ev->delta() > 0 ? Qt::Key_Up : Qt::Key_Down; | 2380 } |
2272 | 2381 |
2273 // QWheelEvent::delta() gives rotation in eighths of a degree | 2382 _screenWindow->clearSelection (); |
2274 int wheelDegrees = ev->delta() / 8; | 2383 QPoint bgnSel = pos; |
2275 int linesToScroll = abs(wheelDegrees) / 5; | 2384 QPoint endSel = pos; |
2276 | 2385 int i = loc (bgnSel.x (), bgnSel.y ()); |
2277 QKeyEvent keyScrollEvent(QEvent::KeyPress,key,Qt::NoModifier); | 2386 _iPntSel = bgnSel; |
2278 | 2387 _iPntSel.ry () += _scrollBar->value (); |
2279 for (int i=0;i<linesToScroll;i++) | 2388 |
2280 emit keyPressedSignal(&keyScrollEvent); | 2389 _wordSelectionMode = true; |
2281 } | 2390 |
2282 } | 2391 // find word boundaries... |
2283 else | 2392 QChar selClass = charClass (_image[i].character); |
2284 { | 2393 { |
2285 // terminal program wants notification of mouse activity | 2394 // find the start of the word |
2286 | 2395 int x = bgnSel.x (); |
2287 int charLine; | 2396 while (((x > 0) |
2288 int charColumn; | 2397 || (bgnSel.y () > 0 |
2289 getCharacterPosition( ev->pos() , charLine , charColumn ); | 2398 && (_lineProperties[bgnSel.y () - 1] & LINE_WRAPPED))) |
2290 | 2399 && charClass (_image[i - 1].character) == selClass) |
2291 emit mouseSignal( ev->delta() > 0 ? 4 : 5, | 2400 { |
2292 charColumn + 1, | 2401 i--; |
2293 charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , | 2402 if (x > 0) |
2294 0); | 2403 x--; |
2295 } | 2404 else |
2296 } | 2405 { |
2297 | 2406 x = _usedColumns - 1; |
2298 void TerminalDisplay::tripleClickTimeout() | 2407 bgnSel.ry ()--; |
2299 { | 2408 } |
2300 _possibleTripleClick=false; | 2409 } |
2301 } | 2410 |
2302 | 2411 bgnSel.setX (x); |
2303 void TerminalDisplay::mouseTripleClickEvent(QMouseEvent* ev) | 2412 _screenWindow->setSelectionStart (bgnSel.x (), bgnSel.y (), false); |
2304 { | 2413 |
2305 if ( !_screenWindow ) return; | 2414 // find the end of the word |
2306 | 2415 i = loc (endSel.x (), endSel.y ()); |
2307 int charLine; | 2416 x = endSel.x (); |
2308 int charColumn; | 2417 while (((x < _usedColumns - 1) |
2309 getCharacterPosition(ev->pos(),charLine,charColumn); | 2418 || (endSel.y () < _usedLines - 1 |
2310 _iPntSel = QPoint(charColumn,charLine); | 2419 && (_lineProperties[endSel.y ()] & LINE_WRAPPED))) |
2311 | 2420 && charClass (_image[i + 1].character) == selClass) |
2312 _screenWindow->clearSelection(); | 2421 { |
2313 | 2422 i++; |
2314 _lineSelectionMode = true; | 2423 if (x < _usedColumns - 1) |
2315 _wordSelectionMode = false; | 2424 x++; |
2316 | 2425 else |
2317 _actSel = 2; // within selection | 2426 { |
2318 emit isBusySelecting(true); // Keep it steady... | 2427 x = 0; |
2319 | 2428 endSel.ry ()++; |
2320 while (_iPntSel.y()>0 && (_lineProperties[_iPntSel.y()-1] & LINE_WRAPPED) ) | 2429 } |
2321 _iPntSel.ry()--; | 2430 } |
2322 | 2431 |
2323 if (_tripleClickMode == SelectForwardsFromCursor) { | 2432 endSel.setX (x); |
2324 // find word boundary start | 2433 |
2325 int i = loc(_iPntSel.x(),_iPntSel.y()); | 2434 // In word selection mode don't select @ (64) if at end of word. |
2326 QChar selClass = charClass(_image[i].character); | 2435 if ((QChar (_image[i].character) == '@') |
2327 int x = _iPntSel.x(); | 2436 && ((endSel.x () - bgnSel.x ()) > 0)) |
2328 | 2437 endSel.setX (x - 1); |
2329 while ( ((x>0) || | 2438 |
2330 (_iPntSel.y()>0 && (_lineProperties[_iPntSel.y()-1] & LINE_WRAPPED) ) | 2439 |
2331 ) | 2440 _actSel = 2; // within selection |
2332 && charClass(_image[i-1].character) == selClass ) | 2441 |
2333 { | 2442 _screenWindow->setSelectionEnd (endSel.x (), endSel.y ()); |
2334 i--; | 2443 |
2335 if (x>0) | 2444 setSelection (_screenWindow->selectedText (_preserveLineBreaks)); |
2336 x--; | 2445 } |
2337 else | 2446 |
2338 { | 2447 _possibleTripleClick = true; |
2339 x=_columns-1; | 2448 |
2340 _iPntSel.ry()--; | 2449 QTimer::singleShot (QApplication::doubleClickInterval (), this, |
2341 } | 2450 SLOT (tripleClickTimeout ())); |
2342 } | 2451 } |
2343 | 2452 |
2344 _screenWindow->setSelectionStart( x , _iPntSel.y() , false ); | 2453 void |
2345 _tripleSelBegin = QPoint( x, _iPntSel.y() ); | 2454 TerminalDisplay::wheelEvent (QWheelEvent * ev) |
2346 } | 2455 { |
2347 else if (_tripleClickMode == SelectWholeLine) { | 2456 if (ev->orientation () != Qt::Vertical) |
2348 _screenWindow->setSelectionStart( 0 , _iPntSel.y() , false ); | 2457 return; |
2349 _tripleSelBegin = QPoint( 0, _iPntSel.y() ); | 2458 |
2350 } | 2459 // if the terminal program is not interested mouse events |
2351 | 2460 // then send the event to the scrollbar if the slider has room to move |
2352 while (_iPntSel.y()<_lines-1 && (_lineProperties[_iPntSel.y()] & LINE_WRAPPED) ) | 2461 // or otherwise send simulated up / down key presses to the terminal program |
2353 _iPntSel.ry()++; | 2462 // for the benefit of programs such as 'less' |
2354 | 2463 if (_mouseMarks) |
2355 _screenWindow->setSelectionEnd( _columns - 1 , _iPntSel.y() ); | 2464 { |
2356 | 2465 bool canScroll = _scrollBar->maximum () > 0; |
2357 setSelection(_screenWindow->selectedText(_preserveLineBreaks)); | 2466 if (canScroll) |
2358 | 2467 _scrollBar->event (ev); |
2359 _iPntSel.ry() += _scrollBar->value(); | 2468 else |
2360 } | 2469 { |
2361 | 2470 // assume that each Up / Down key event will cause the terminal application |
2362 | 2471 // to scroll by one line. |
2363 bool TerminalDisplay::focusNextPrevChild( bool next ) | 2472 // |
2364 { | 2473 // to get a reasonable scrolling speed, scroll by one line for every 5 degrees |
2365 if (next) | 2474 // of mouse wheel rotation. Mouse wheels typically move in steps of 15 degrees, |
2366 return false; // This disables changing the active part in konqueror | 2475 // giving a scroll of 3 lines |
2367 // when pressing Tab | 2476 int key = ev->delta () > 0 ? Qt::Key_Up : Qt::Key_Down; |
2368 return QWidget::focusNextPrevChild( next ); | 2477 |
2369 } | 2478 // QWheelEvent::delta() gives rotation in eighths of a degree |
2370 | 2479 int wheelDegrees = ev->delta () / 8; |
2371 | 2480 int linesToScroll = abs (wheelDegrees) / 5; |
2372 QChar TerminalDisplay::charClass(QChar qch) const | 2481 |
2373 { | 2482 QKeyEvent keyScrollEvent (QEvent::KeyPress, key, Qt::NoModifier); |
2374 if ( qch.isSpace() ) return ' '; | 2483 |
2375 | 2484 for (int i = 0; i < linesToScroll; i++) |
2376 if ( qch.isLetterOrNumber() || _wordCharacters.contains(qch, Qt::CaseInsensitive ) ) | 2485 emit keyPressedSignal (&keyScrollEvent); |
2377 return 'a'; | 2486 } |
2378 | 2487 } |
2379 return qch; | 2488 else |
2380 } | 2489 { |
2381 | 2490 // terminal program wants notification of mouse activity |
2382 void TerminalDisplay::setWordCharacters(const QString& wc) | 2491 |
2383 { | 2492 int charLine; |
2384 _wordCharacters = wc; | 2493 int charColumn; |
2385 } | 2494 getCharacterPosition (ev->pos (), charLine, charColumn); |
2386 | 2495 |
2387 void TerminalDisplay::setUsesMouse(bool on) | 2496 emit mouseSignal (ev->delta () > 0 ? 4 : 5, |
2388 { | 2497 charColumn + 1, |
2389 _mouseMarks = on; | 2498 charLine + 1 + _scrollBar->value () - |
2390 setCursor( _mouseMarks ? Qt::IBeamCursor : Qt::ArrowCursor ); | 2499 _scrollBar->maximum (), 0); |
2391 } | 2500 } |
2392 bool TerminalDisplay::usesMouse() const | 2501 } |
2393 { | 2502 |
2394 return _mouseMarks; | 2503 void |
2504 TerminalDisplay::tripleClickTimeout () | |
2505 { | |
2506 _possibleTripleClick = false; | |
2507 } | |
2508 | |
2509 void | |
2510 TerminalDisplay::mouseTripleClickEvent (QMouseEvent * ev) | |
2511 { | |
2512 if (!_screenWindow) | |
2513 return; | |
2514 | |
2515 int charLine; | |
2516 int charColumn; | |
2517 getCharacterPosition (ev->pos (), charLine, charColumn); | |
2518 _iPntSel = QPoint (charColumn, charLine); | |
2519 | |
2520 _screenWindow->clearSelection (); | |
2521 | |
2522 _lineSelectionMode = true; | |
2523 _wordSelectionMode = false; | |
2524 | |
2525 _actSel = 2; // within selection | |
2526 emit isBusySelecting (true); // Keep it steady... | |
2527 | |
2528 while (_iPntSel.y () > 0 | |
2529 && (_lineProperties[_iPntSel.y () - 1] & LINE_WRAPPED)) | |
2530 _iPntSel.ry ()--; | |
2531 | |
2532 if (_tripleClickMode == SelectForwardsFromCursor) | |
2533 { | |
2534 // find word boundary start | |
2535 int i = loc (_iPntSel.x (), _iPntSel.y ()); | |
2536 QChar selClass = charClass (_image[i].character); | |
2537 int x = _iPntSel.x (); | |
2538 | |
2539 while (((x > 0) || | |
2540 (_iPntSel.y () > 0 | |
2541 && (_lineProperties[_iPntSel.y () - 1] & LINE_WRAPPED))) | |
2542 && charClass (_image[i - 1].character) == selClass) | |
2543 { | |
2544 i--; | |
2545 if (x > 0) | |
2546 x--; | |
2547 else | |
2548 { | |
2549 x = _columns - 1; | |
2550 _iPntSel.ry ()--; | |
2551 } | |
2552 } | |
2553 | |
2554 _screenWindow->setSelectionStart (x, _iPntSel.y (), false); | |
2555 _tripleSelBegin = QPoint (x, _iPntSel.y ()); | |
2556 } | |
2557 else if (_tripleClickMode == SelectWholeLine) | |
2558 { | |
2559 _screenWindow->setSelectionStart (0, _iPntSel.y (), false); | |
2560 _tripleSelBegin = QPoint (0, _iPntSel.y ()); | |
2561 } | |
2562 | |
2563 while (_iPntSel.y () < _lines - 1 | |
2564 && (_lineProperties[_iPntSel.y ()] & LINE_WRAPPED)) | |
2565 _iPntSel.ry ()++; | |
2566 | |
2567 _screenWindow->setSelectionEnd (_columns - 1, _iPntSel.y ()); | |
2568 | |
2569 setSelection (_screenWindow->selectedText (_preserveLineBreaks)); | |
2570 | |
2571 _iPntSel.ry () += _scrollBar->value (); | |
2572 } | |
2573 | |
2574 | |
2575 bool | |
2576 TerminalDisplay::focusNextPrevChild (bool next) | |
2577 { | |
2578 if (next) | |
2579 return false; // This disables changing the active part in konqueror | |
2580 // when pressing Tab | |
2581 return QWidget::focusNextPrevChild (next); | |
2582 } | |
2583 | |
2584 | |
2585 QChar | |
2586 TerminalDisplay::charClass (QChar qch) const | |
2587 { | |
2588 if (qch.isSpace ()) | |
2589 return ' '; | |
2590 | |
2591 if (qch.isLetterOrNumber () | |
2592 || _wordCharacters.contains (qch, Qt::CaseInsensitive)) | |
2593 return 'a'; | |
2594 | |
2595 return qch; | |
2596 } | |
2597 | |
2598 void | |
2599 TerminalDisplay::setWordCharacters (const QString & wc) | |
2600 { | |
2601 _wordCharacters = wc; | |
2602 } | |
2603 | |
2604 void | |
2605 TerminalDisplay::setUsesMouse (bool on) | |
2606 { | |
2607 _mouseMarks = on; | |
2608 setCursor (_mouseMarks ? Qt::IBeamCursor : Qt::ArrowCursor); | |
2609 } | |
2610 | |
2611 bool | |
2612 TerminalDisplay::usesMouse () const | |
2613 { | |
2614 return _mouseMarks; | |
2395 } | 2615 } |
2396 | 2616 |
2397 /* ------------------------------------------------------------------------- */ | 2617 /* ------------------------------------------------------------------------- */ |
2398 /* */ | 2618 /* */ |
2399 /* Clipboard */ | 2619 /* Clipboard */ |
2400 /* */ | 2620 /* */ |
2401 /* ------------------------------------------------------------------------- */ | 2621 /* ------------------------------------------------------------------------- */ |
2402 | 2622 |
2403 #undef KeyPress | 2623 #undef KeyPress |
2404 | 2624 |
2405 void TerminalDisplay::emitSelection(bool useXselection,bool appendReturn) | 2625 void |
2406 { | 2626 TerminalDisplay::emitSelection (bool useXselection, bool appendReturn) |
2407 if ( !_screenWindow ) | 2627 { |
2408 return; | 2628 if (!_screenWindow) |
2409 | 2629 return; |
2410 // Paste Clipboard by simulating keypress events | 2630 |
2411 QString text = QApplication::clipboard()->text(useXselection ? QClipboard::Selection : | 2631 // Paste Clipboard by simulating keypress events |
2412 QClipboard::Clipboard); | 2632 QString text = |
2413 if(appendReturn) | 2633 QApplication::clipboard ()-> |
2414 text.append("\r"); | 2634 text (useXselection ? QClipboard::Selection : QClipboard::Clipboard); |
2415 if ( ! text.isEmpty() ) | 2635 if (appendReturn) |
2416 { | 2636 text.append ("\r"); |
2417 text.replace('\n', '\r'); | 2637 if (!text.isEmpty ()) |
2418 QKeyEvent e(QEvent::KeyPress, 0, Qt::NoModifier, text); | 2638 { |
2419 emit keyPressedSignal(&e); // expose as a big fat keypress event | 2639 text.replace ('\n', '\r'); |
2420 | 2640 QKeyEvent e (QEvent::KeyPress, 0, Qt::NoModifier, text); |
2421 _screenWindow->clearSelection(); | 2641 emit keyPressedSignal (&e); // expose as a big fat keypress event |
2422 } | 2642 |
2423 } | 2643 _screenWindow->clearSelection (); |
2424 | 2644 } |
2425 void TerminalDisplay::setSelection(const QString& t) | 2645 } |
2426 { | 2646 |
2427 QApplication::clipboard()->setText(t, QClipboard::Selection); | 2647 void |
2428 } | 2648 TerminalDisplay::setSelection (const QString & t) |
2429 | 2649 { |
2430 void TerminalDisplay::copyClipboard() | 2650 QApplication::clipboard ()->setText (t, QClipboard::Selection); |
2431 { | 2651 } |
2432 if ( !_screenWindow ) | 2652 |
2433 return; | 2653 void |
2434 | 2654 TerminalDisplay::copyClipboard () |
2435 QString text = _screenWindow->selectedText(_preserveLineBreaks); | 2655 { |
2436 if (!text.isEmpty()) | 2656 if (!_screenWindow) |
2437 QApplication::clipboard()->setText(text); | 2657 return; |
2438 } | 2658 |
2439 | 2659 QString text = _screenWindow->selectedText (_preserveLineBreaks); |
2440 void TerminalDisplay::pasteClipboard() | 2660 if (!text.isEmpty ()) |
2441 { | 2661 QApplication::clipboard ()->setText (text); |
2442 emitSelection(false,false); | 2662 } |
2443 } | 2663 |
2444 | 2664 void |
2445 void TerminalDisplay::pasteSelection() | 2665 TerminalDisplay::pasteClipboard () |
2446 { | 2666 { |
2447 emitSelection(true,false); | 2667 emitSelection (false, false); |
2668 } | |
2669 | |
2670 void | |
2671 TerminalDisplay::pasteSelection () | |
2672 { | |
2673 emitSelection (true, false); | |
2448 } | 2674 } |
2449 | 2675 |
2450 /* ------------------------------------------------------------------------- */ | 2676 /* ------------------------------------------------------------------------- */ |
2451 /* */ | 2677 /* */ |
2452 /* Keyboard */ | 2678 /* Keyboard */ |
2453 /* */ | 2679 /* */ |
2454 /* ------------------------------------------------------------------------- */ | 2680 /* ------------------------------------------------------------------------- */ |
2455 | 2681 |
2456 void TerminalDisplay::setFlowControlWarningEnabled( bool enable ) | 2682 void |
2457 { | 2683 TerminalDisplay::setFlowControlWarningEnabled (bool enable) |
2458 _flowControlWarningEnabled = enable; | 2684 { |
2459 | 2685 _flowControlWarningEnabled = enable; |
2460 // if the dialog is currently visible and the flow control warning has | 2686 |
2461 // been disabled then hide the dialog | 2687 // if the dialog is currently visible and the flow control warning has |
2462 if (!enable) | 2688 // been disabled then hide the dialog |
2463 outputSuspended(false); | 2689 if (!enable) |
2464 } | 2690 outputSuspended (false); |
2465 | 2691 } |
2466 void TerminalDisplay::keyPressEvent( QKeyEvent* event ) | 2692 |
2467 { | 2693 void |
2468 bool emitKeyPressSignal = true; | 2694 TerminalDisplay::keyPressEvent (QKeyEvent * event) |
2469 | 2695 { |
2470 if(event->modifiers() == Qt::ControlModifier) | 2696 bool emitKeyPressSignal = true; |
2471 { | 2697 |
2472 switch(event->key()) { | 2698 if (event->modifiers () == Qt::ControlModifier) |
2473 case Qt::Key_C: | 2699 { |
2474 copyClipboard(); | 2700 switch (event->key ()) |
2475 break; | 2701 { |
2476 case Qt::Key_V: | 2702 case Qt::Key_C: |
2477 pasteClipboard(); | 2703 copyClipboard (); |
2478 break; | 2704 break; |
2479 }; | 2705 case Qt::Key_V: |
2480 } else if ( event->modifiers() == Qt::ShiftModifier ) { | 2706 pasteClipboard (); |
2481 bool update = true; | 2707 break; |
2482 | 2708 }; |
2483 if ( event->key() == Qt::Key_PageUp ) | 2709 } |
2484 { | 2710 else if (event->modifiers () == Qt::ShiftModifier) |
2485 _screenWindow->scrollBy( ScreenWindow::ScrollPages , -1 ); | 2711 { |
2486 } | 2712 bool update = true; |
2487 else if ( event->key() == Qt::Key_PageDown ) | 2713 |
2488 { | 2714 if (event->key () == Qt::Key_PageUp) |
2489 _screenWindow->scrollBy( ScreenWindow::ScrollPages , 1 ); | 2715 { |
2490 } | 2716 _screenWindow->scrollBy (ScreenWindow::ScrollPages, -1); |
2491 else if ( event->key() == Qt::Key_Up ) | 2717 } |
2492 { | 2718 else if (event->key () == Qt::Key_PageDown) |
2493 _screenWindow->scrollBy( ScreenWindow::ScrollLines , -1 ); | 2719 { |
2494 } | 2720 _screenWindow->scrollBy (ScreenWindow::ScrollPages, 1); |
2495 else if ( event->key() == Qt::Key_Down ) | 2721 } |
2496 { | 2722 else if (event->key () == Qt::Key_Up) |
2497 _screenWindow->scrollBy( ScreenWindow::ScrollLines , 1 ); | 2723 { |
2498 } | 2724 _screenWindow->scrollBy (ScreenWindow::ScrollLines, -1); |
2499 else | 2725 } |
2500 update = false; | 2726 else if (event->key () == Qt::Key_Down) |
2501 | 2727 { |
2502 if ( update ) | 2728 _screenWindow->scrollBy (ScreenWindow::ScrollLines, 1); |
2503 { | 2729 } |
2504 _screenWindow->setTrackOutput( _screenWindow->atEndOfOutput() ); | 2730 else |
2505 | 2731 update = false; |
2506 updateLineProperties(); | 2732 |
2507 updateImage(); | 2733 if (update) |
2508 | 2734 { |
2509 // do not send key press to terminal | 2735 _screenWindow->setTrackOutput (_screenWindow->atEndOfOutput ()); |
2510 emitKeyPressSignal = false; | 2736 |
2511 } | 2737 updateLineProperties (); |
2512 } | 2738 updateImage (); |
2513 | 2739 |
2514 _actSel=0; // Key stroke implies a screen update, so TerminalDisplay won't | 2740 // do not send key press to terminal |
2515 // know where the current selection is. | 2741 emitKeyPressSignal = false; |
2516 | 2742 } |
2517 if (_hasBlinkingCursor) | 2743 } |
2518 { | 2744 |
2519 _blinkCursorTimer->start(QApplication::cursorFlashTime() / 2); | 2745 _actSel = 0; // Key stroke implies a screen update, so TerminalDisplay won't |
2520 if (_cursorBlinking) | 2746 // know where the current selection is. |
2521 blinkCursorEvent(); | 2747 |
2522 else | 2748 if (_hasBlinkingCursor) |
2523 _cursorBlinking = false; | 2749 { |
2524 } | 2750 _blinkCursorTimer->start (QApplication::cursorFlashTime () / 2); |
2525 | 2751 if (_cursorBlinking) |
2526 if ( emitKeyPressSignal ) | 2752 blinkCursorEvent (); |
2527 emit keyPressedSignal(event); | 2753 else |
2528 | 2754 _cursorBlinking = false; |
2529 event->accept(); | 2755 } |
2530 } | 2756 |
2531 | 2757 if (emitKeyPressSignal) |
2532 void TerminalDisplay::inputMethodEvent( QInputMethodEvent* event ) | 2758 emit keyPressedSignal (event); |
2533 { | 2759 |
2534 QKeyEvent keyEvent(QEvent::KeyPress,0,(Qt::KeyboardModifiers)Qt::NoModifier,event->commitString()); | 2760 event->accept (); |
2535 emit keyPressedSignal(&keyEvent); | 2761 } |
2536 | 2762 |
2537 _inputMethodData.preeditString = event->preeditString(); | 2763 void |
2538 update(preeditRect() | _inputMethodData.previousPreeditRect); | 2764 TerminalDisplay::inputMethodEvent (QInputMethodEvent * event) |
2539 | 2765 { |
2540 event->accept(); | 2766 QKeyEvent keyEvent (QEvent::KeyPress, 0, |
2541 } | 2767 (Qt::KeyboardModifiers) Qt::NoModifier, |
2542 QVariant TerminalDisplay::inputMethodQuery( Qt::InputMethodQuery query ) const | 2768 event->commitString ()); |
2543 { | 2769 emit keyPressedSignal (&keyEvent); |
2544 const QPoint cursorPos = _screenWindow ? _screenWindow->cursorPosition() : QPoint(0,0); | 2770 |
2545 switch ( query ) | 2771 _inputMethodData.preeditString = event->preeditString (); |
2772 update (preeditRect () | _inputMethodData.previousPreeditRect); | |
2773 | |
2774 event->accept (); | |
2775 } | |
2776 | |
2777 QVariant | |
2778 TerminalDisplay::inputMethodQuery (Qt::InputMethodQuery query) const | |
2779 { | |
2780 const QPoint cursorPos = | |
2781 _screenWindow ? _screenWindow->cursorPosition () : QPoint (0, 0); | |
2782 switch (query) | |
2546 { | 2783 { |
2547 case Qt::ImMicroFocus: | 2784 case Qt::ImMicroFocus: |
2548 return imageToWidget(QRect(cursorPos.x(),cursorPos.y(),1,1)); | 2785 return imageToWidget (QRect (cursorPos.x (), cursorPos.y (), 1, 1)); |
2549 break; | 2786 break; |
2550 case Qt::ImFont: | 2787 case Qt::ImFont: |
2551 return font(); | 2788 return font (); |
2552 break; | 2789 break; |
2553 case Qt::ImCursorPosition: | 2790 case Qt::ImCursorPosition: |
2554 // return the cursor position within the current line | 2791 // return the cursor position within the current line |
2555 return cursorPos.x(); | 2792 return cursorPos.x (); |
2556 break; | 2793 break; |
2557 case Qt::ImSurroundingText: | 2794 case Qt::ImSurroundingText: |
2558 { | 2795 { |
2559 // return the text from the current line | 2796 // return the text from the current line |
2560 QString lineText; | 2797 QString lineText; |
2561 QTextStream stream(&lineText); | 2798 QTextStream stream (&lineText); |
2562 PlainTextDecoder decoder; | 2799 PlainTextDecoder decoder; |
2563 decoder.begin(&stream); | 2800 decoder.begin (&stream); |
2564 decoder.decodeLine(&_image[loc(0,cursorPos.y())],_usedColumns,_lineProperties[cursorPos.y()]); | 2801 decoder.decodeLine (&_image[loc (0, cursorPos.y ())], _usedColumns, |
2565 decoder.end(); | 2802 _lineProperties[cursorPos.y ()]); |
2566 return lineText; | 2803 decoder.end (); |
2567 } | 2804 return lineText; |
2568 break; | 2805 } |
2806 break; | |
2569 case Qt::ImCurrentSelection: | 2807 case Qt::ImCurrentSelection: |
2570 return QString(); | 2808 return QString (); |
2571 break; | 2809 break; |
2572 default: | 2810 default: |
2573 break; | 2811 break; |
2574 } | 2812 } |
2575 | 2813 |
2576 return QVariant(); | 2814 return QVariant (); |
2577 } | 2815 } |
2578 | 2816 |
2579 bool TerminalDisplay::handleShortcutOverrideEvent(QKeyEvent* keyEvent) | 2817 bool |
2580 { | 2818 TerminalDisplay::handleShortcutOverrideEvent (QKeyEvent * keyEvent) |
2581 int modifiers = keyEvent->modifiers(); | 2819 { |
2582 | 2820 int modifiers = keyEvent->modifiers (); |
2583 // When a possible shortcut combination is pressed, | 2821 |
2584 // emit the overrideShortcutCheck() signal to allow the host | 2822 // When a possible shortcut combination is pressed, |
2585 // to decide whether the terminal should override it or not. | 2823 // emit the overrideShortcutCheck() signal to allow the host |
2586 if (modifiers != Qt::NoModifier) | 2824 // to decide whether the terminal should override it or not. |
2587 { | 2825 if (modifiers != Qt::NoModifier) |
2588 int modifierCount = 0; | 2826 { |
2589 unsigned int currentModifier = Qt::ShiftModifier; | 2827 int modifierCount = 0; |
2590 | 2828 unsigned int currentModifier = Qt::ShiftModifier; |
2591 while (currentModifier <= Qt::KeypadModifier) | 2829 |
2592 { | 2830 while (currentModifier <= Qt::KeypadModifier) |
2593 if (modifiers & currentModifier) | 2831 { |
2594 modifierCount++; | 2832 if (modifiers & currentModifier) |
2595 currentModifier <<= 1; | 2833 modifierCount++; |
2596 } | 2834 currentModifier <<= 1; |
2597 if (modifierCount < 2) | 2835 } |
2598 { | 2836 if (modifierCount < 2) |
2599 bool override = false; | 2837 { |
2600 emit overrideShortcutCheck(keyEvent,override); | 2838 bool override = false; |
2601 if (override) | 2839 emit overrideShortcutCheck (keyEvent, override); |
2602 { | 2840 if (override) |
2603 keyEvent->accept(); | 2841 { |
2604 return true; | 2842 keyEvent->accept (); |
2605 } | 2843 return true; |
2606 } | 2844 } |
2607 } | 2845 } |
2608 | 2846 } |
2609 // Override any of the following shortcuts because | 2847 |
2610 // they are needed by the terminal | 2848 // Override any of the following shortcuts because |
2611 int keyCode = keyEvent->key() | modifiers; | 2849 // they are needed by the terminal |
2612 switch ( keyCode ) | 2850 int keyCode = keyEvent->key () | modifiers; |
2613 { | 2851 switch (keyCode) |
2614 // list is taken from the QLineEdit::event() code | 2852 { |
2853 // list is taken from the QLineEdit::event() code | |
2615 case Qt::Key_Tab: | 2854 case Qt::Key_Tab: |
2616 case Qt::Key_Delete: | 2855 case Qt::Key_Delete: |
2617 case Qt::Key_Home: | 2856 case Qt::Key_Home: |
2618 case Qt::Key_End: | 2857 case Qt::Key_End: |
2619 case Qt::Key_Backspace: | 2858 case Qt::Key_Backspace: |
2620 case Qt::Key_Left: | 2859 case Qt::Key_Left: |
2621 case Qt::Key_Right: | 2860 case Qt::Key_Right: |
2622 keyEvent->accept(); | 2861 keyEvent->accept (); |
2623 return true; | 2862 return true; |
2624 } | 2863 } |
2625 return false; | 2864 return false; |
2626 } | 2865 } |
2627 | 2866 |
2628 bool TerminalDisplay::event(QEvent* event) | 2867 bool |
2629 { | 2868 TerminalDisplay::event (QEvent * event) |
2630 bool eventHandled = false; | 2869 { |
2631 switch (event->type()) | 2870 bool eventHandled = false; |
2871 switch (event->type ()) | |
2632 { | 2872 { |
2633 case QEvent::ShortcutOverride: | 2873 case QEvent::ShortcutOverride: |
2634 eventHandled = handleShortcutOverrideEvent((QKeyEvent*)event); | 2874 eventHandled = handleShortcutOverrideEvent ((QKeyEvent *) event); |
2635 break; | 2875 break; |
2636 case QEvent::PaletteChange: | 2876 case QEvent::PaletteChange: |
2637 case QEvent::ApplicationPaletteChange: | 2877 case QEvent::ApplicationPaletteChange: |
2638 _scrollBar->setPalette( QApplication::palette() ); | 2878 _scrollBar->setPalette (QApplication::palette ()); |
2639 break; | 2879 break; |
2640 default: | 2880 default: |
2641 break; | 2881 break; |
2642 } | 2882 } |
2643 return eventHandled ? true : QWidget::event(event); | 2883 return eventHandled ? true : QWidget::event (event); |
2644 } | 2884 } |
2645 | 2885 |
2646 void TerminalDisplay::setBellMode(int mode) | 2886 void |
2647 { | 2887 TerminalDisplay::setBellMode (int mode) |
2648 _bellMode=mode; | 2888 { |
2649 } | 2889 _bellMode = mode; |
2650 | 2890 } |
2651 void TerminalDisplay::enableBell() | 2891 |
2652 { | 2892 void |
2653 _allowBell = true; | 2893 TerminalDisplay::enableBell () |
2654 } | 2894 { |
2655 | 2895 _allowBell = true; |
2656 void TerminalDisplay::bell(const QString& message) | 2896 } |
2657 { | 2897 |
2658 Q_UNUSED(message); | 2898 void |
2659 if (_bellMode==NoBell) return; | 2899 TerminalDisplay::bell (const QString & message) |
2660 | 2900 { |
2661 //limit the rate at which bells can occur | 2901 Q_UNUSED (message); |
2662 //...mainly for sound effects where rapid bells in sequence | 2902 if (_bellMode == NoBell) |
2663 //produce a horrible noise | 2903 return; |
2664 if ( _allowBell ) | 2904 |
2665 { | 2905 //limit the rate at which bells can occur |
2666 _allowBell = false; | 2906 //...mainly for sound effects where rapid bells in sequence |
2667 QTimer::singleShot(500,this,SLOT(enableBell())); | 2907 //produce a horrible noise |
2668 | 2908 if (_allowBell) |
2669 if (_bellMode==SystemBeepBell) | 2909 { |
2670 { | 2910 _allowBell = false; |
2671 // TODO: This will need added back in at some point | 2911 QTimer::singleShot (500, this, SLOT (enableBell ())); |
2672 //KNotification::beep(); | 2912 |
2673 } | 2913 if (_bellMode == SystemBeepBell) |
2674 else if (_bellMode==NotifyBell) | 2914 { |
2675 { | 2915 // TODO: This will need added back in at some point |
2676 // TODO: This will need added back in at some point | 2916 //KNotification::beep(); |
2677 //KNotification::event("BellVisible", message,QPixmap(),this); | 2917 } |
2678 } | 2918 else if (_bellMode == NotifyBell) |
2679 else if (_bellMode==VisualBell) | 2919 { |
2680 { | 2920 // TODO: This will need added back in at some point |
2681 swapColorTable(); | 2921 //KNotification::event("BellVisible", message,QPixmap(),this); |
2682 QTimer::singleShot(200,this,SLOT(swapColorTable())); | 2922 } |
2683 } | 2923 else if (_bellMode == VisualBell) |
2684 } | 2924 { |
2685 } | 2925 swapColorTable (); |
2686 | 2926 QTimer::singleShot (200, this, SLOT (swapColorTable ())); |
2687 void TerminalDisplay::swapColorTable() | 2927 } |
2688 { | 2928 } |
2689 ColorEntry color = _colorTable[1]; | 2929 } |
2690 _colorTable[1]=_colorTable[0]; | 2930 |
2691 _colorTable[0]= color; | 2931 void |
2692 _colorsInverted = !_colorsInverted; | 2932 TerminalDisplay::swapColorTable () |
2693 update(); | 2933 { |
2694 } | 2934 ColorEntry color = _colorTable[1]; |
2695 | 2935 _colorTable[1] = _colorTable[0]; |
2696 void TerminalDisplay::clearImage() | 2936 _colorTable[0] = color; |
2697 { | 2937 _colorsInverted = !_colorsInverted; |
2698 // We initialize _image[_imageSize] too. See makeImage() | 2938 update (); |
2699 for (int i = 0; i <= _imageSize; i++) | 2939 } |
2700 { | 2940 |
2701 _image[i].character = ' '; | 2941 void |
2702 _image[i].foregroundColor = CharacterColor(COLOR_SPACE_DEFAULT, | 2942 TerminalDisplay::clearImage () |
2703 DEFAULT_FORE_COLOR); | 2943 { |
2704 _image[i].backgroundColor = CharacterColor(COLOR_SPACE_DEFAULT, | 2944 // We initialize _image[_imageSize] too. See makeImage() |
2705 DEFAULT_BACK_COLOR); | 2945 for (int i = 0; i <= _imageSize; i++) |
2706 _image[i].rendition = DEFAULT_RENDITION; | 2946 { |
2707 } | 2947 _image[i].character = ' '; |
2708 } | 2948 _image[i].foregroundColor = CharacterColor (COLOR_SPACE_DEFAULT, |
2709 | 2949 DEFAULT_FORE_COLOR); |
2710 void TerminalDisplay::calcGeometry() | 2950 _image[i].backgroundColor = CharacterColor (COLOR_SPACE_DEFAULT, |
2711 { | 2951 DEFAULT_BACK_COLOR); |
2712 _scrollBar->resize(_scrollBar->sizeHint().width(), contentsRect().height()); | 2952 _image[i].rendition = DEFAULT_RENDITION; |
2713 switch(_scrollbarLocation) | 2953 } |
2714 { | 2954 } |
2715 case NoScrollBar : | 2955 |
2716 _leftMargin = DEFAULT_LEFT_MARGIN; | 2956 void |
2717 _contentWidth = contentsRect().width() - 2 * DEFAULT_LEFT_MARGIN; | 2957 TerminalDisplay::calcGeometry () |
2718 break; | 2958 { |
2719 case ScrollBarLeft : | 2959 _scrollBar->resize (_scrollBar->sizeHint ().width (), |
2720 _leftMargin = DEFAULT_LEFT_MARGIN + _scrollBar->width(); | 2960 contentsRect ().height ()); |
2721 _contentWidth = contentsRect().width() - 2 * DEFAULT_LEFT_MARGIN - _scrollBar->width(); | 2961 switch (_scrollbarLocation) |
2722 _scrollBar->move(contentsRect().topLeft()); | 2962 { |
2723 break; | 2963 case NoScrollBar: |
2964 _leftMargin = DEFAULT_LEFT_MARGIN; | |
2965 _contentWidth = contentsRect ().width () - 2 * DEFAULT_LEFT_MARGIN; | |
2966 break; | |
2967 case ScrollBarLeft: | |
2968 _leftMargin = DEFAULT_LEFT_MARGIN + _scrollBar->width (); | |
2969 _contentWidth = | |
2970 contentsRect ().width () - 2 * DEFAULT_LEFT_MARGIN - | |
2971 _scrollBar->width (); | |
2972 _scrollBar->move (contentsRect ().topLeft ()); | |
2973 break; | |
2724 case ScrollBarRight: | 2974 case ScrollBarRight: |
2725 _leftMargin = DEFAULT_LEFT_MARGIN; | 2975 _leftMargin = DEFAULT_LEFT_MARGIN; |
2726 _contentWidth = contentsRect().width() - 2 * DEFAULT_LEFT_MARGIN - _scrollBar->width(); | 2976 _contentWidth = |
2727 _scrollBar->move(contentsRect().topRight() - QPoint(_scrollBar->width()-1,0)); | 2977 contentsRect ().width () - 2 * DEFAULT_LEFT_MARGIN - |
2728 break; | 2978 _scrollBar->width (); |
2729 } | 2979 _scrollBar->move (contentsRect ().topRight () - |
2730 | 2980 QPoint (_scrollBar->width () - 1, 0)); |
2731 _topMargin = DEFAULT_TOP_MARGIN; | 2981 break; |
2732 _contentHeight = contentsRect().height() - 2 * DEFAULT_TOP_MARGIN + /* mysterious */ 1; | 2982 } |
2733 | 2983 |
2734 if (!_isFixedSize) | 2984 _topMargin = DEFAULT_TOP_MARGIN; |
2735 { | 2985 _contentHeight = |
2736 // ensure that display is always at least one column wide | 2986 contentsRect ().height () - 2 * DEFAULT_TOP_MARGIN + /* mysterious */ 1; |
2737 _columns = qMax(1,_contentWidth / _fontWidth); | 2987 |
2738 _usedColumns = qMin(_usedColumns,_columns); | 2988 if (!_isFixedSize) |
2739 | 2989 { |
2740 // ensure that display is always at least one line high | 2990 // ensure that display is always at least one column wide |
2741 _lines = qMax(1,_contentHeight / _fontHeight); | 2991 _columns = qMax (1, _contentWidth / _fontWidth); |
2742 _usedLines = qMin(_usedLines,_lines); | 2992 _usedColumns = qMin (_usedColumns, _columns); |
2743 } | 2993 |
2744 } | 2994 // ensure that display is always at least one line high |
2745 | 2995 _lines = qMax (1, _contentHeight / _fontHeight); |
2746 void TerminalDisplay::makeImage() | 2996 _usedLines = qMin (_usedLines, _lines); |
2747 { | 2997 } |
2748 calcGeometry(); | 2998 } |
2749 | 2999 |
2750 // confirm that array will be of non-zero size, since the painting code | 3000 void |
2751 // assumes a non-zero array length | 3001 TerminalDisplay::makeImage () |
2752 Q_ASSERT( _lines > 0 && _columns > 0 ); | 3002 { |
2753 Q_ASSERT( _usedLines <= _lines && _usedColumns <= _columns ); | 3003 calcGeometry (); |
2754 | 3004 |
2755 _imageSize=_lines*_columns; | 3005 // confirm that array will be of non-zero size, since the painting code |
2756 | 3006 // assumes a non-zero array length |
2757 // We over-commit one character so that we can be more relaxed in dealing with | 3007 Q_ASSERT (_lines > 0 && _columns > 0); |
2758 // certain boundary conditions: _image[_imageSize] is a valid but unused position | 3008 Q_ASSERT (_usedLines <= _lines && _usedColumns <= _columns); |
2759 _image = new Character[_imageSize+1]; | 3009 |
2760 | 3010 _imageSize = _lines * _columns; |
2761 clearImage(); | 3011 |
3012 // We over-commit one character so that we can be more relaxed in dealing with | |
3013 // certain boundary conditions: _image[_imageSize] is a valid but unused position | |
3014 _image = new Character[_imageSize + 1]; | |
3015 | |
3016 clearImage (); | |
2762 } | 3017 } |
2763 | 3018 |
2764 // calculate the needed size, this must be synced with calcGeometry() | 3019 // calculate the needed size, this must be synced with calcGeometry() |
2765 void TerminalDisplay::setSize(int columns, int lines) | 3020 void |
2766 { | 3021 TerminalDisplay::setSize (int columns, int lines) |
2767 int scrollBarWidth = _scrollBar->isHidden() ? 0 : _scrollBar->sizeHint().width(); | 3022 { |
2768 int horizontalMargin = 2 * DEFAULT_LEFT_MARGIN; | 3023 int scrollBarWidth = |
2769 int verticalMargin = 2 * DEFAULT_TOP_MARGIN; | 3024 _scrollBar->isHidden ()? 0 : _scrollBar->sizeHint ().width (); |
2770 | 3025 int horizontalMargin = 2 * DEFAULT_LEFT_MARGIN; |
2771 QSize newSize = QSize( horizontalMargin + scrollBarWidth + (columns * _fontWidth) , | 3026 int verticalMargin = 2 * DEFAULT_TOP_MARGIN; |
2772 verticalMargin + (lines * _fontHeight) ); | 3027 |
2773 | 3028 QSize newSize = |
2774 if ( newSize != size() ) | 3029 QSize (horizontalMargin + scrollBarWidth + (columns * _fontWidth), |
2775 { | 3030 verticalMargin + (lines * _fontHeight)); |
2776 _size = newSize; | 3031 |
2777 updateGeometry(); | 3032 if (newSize != size ()) |
2778 } | 3033 { |
2779 } | 3034 _size = newSize; |
2780 | 3035 updateGeometry (); |
2781 void TerminalDisplay::setFixedSize(int cols, int lins) | 3036 } |
2782 { | 3037 } |
2783 _isFixedSize = true; | 3038 |
2784 | 3039 void |
2785 //ensure that display is at least one line by one column in size | 3040 TerminalDisplay::setFixedSize (int cols, int lins) |
2786 _columns = qMax(1,cols); | 3041 { |
2787 _lines = qMax(1,lins); | 3042 _isFixedSize = true; |
2788 _usedColumns = qMin(_usedColumns,_columns); | 3043 |
2789 _usedLines = qMin(_usedLines,_lines); | 3044 //ensure that display is at least one line by one column in size |
2790 | 3045 _columns = qMax (1, cols); |
2791 if (_image) | 3046 _lines = qMax (1, lins); |
2792 { | 3047 _usedColumns = qMin (_usedColumns, _columns); |
2793 delete[] _image; | 3048 _usedLines = qMin (_usedLines, _lines); |
2794 makeImage(); | 3049 |
2795 } | 3050 if (_image) |
2796 setSize(cols, lins); | 3051 { |
2797 QWidget::setFixedSize(_size); | 3052 delete[]_image; |
2798 } | 3053 makeImage (); |
2799 | 3054 } |
2800 QSize TerminalDisplay::sizeHint() const | 3055 setSize (cols, lins); |
2801 { | 3056 QWidget::setFixedSize (_size); |
2802 return _size; | 3057 } |
3058 | |
3059 QSize | |
3060 TerminalDisplay::sizeHint () const | |
3061 { | |
3062 return _size; | |
2803 } | 3063 } |
2804 | 3064 |
2805 | 3065 |
2806 /* --------------------------------------------------------------------- */ | 3066 /* --------------------------------------------------------------------- */ |
2807 /* */ | 3067 /* */ |
2808 /* Drag & Drop */ | 3068 /* Drag & Drop */ |
2809 /* */ | 3069 /* */ |
2810 /* --------------------------------------------------------------------- */ | 3070 /* --------------------------------------------------------------------- */ |
2811 | 3071 |
2812 void TerminalDisplay::dragEnterEvent(QDragEnterEvent* event) | 3072 void |
2813 { | 3073 TerminalDisplay::dragEnterEvent (QDragEnterEvent * event) |
2814 if (event->mimeData()->hasFormat("text/plain")) | 3074 { |
2815 event->acceptProposedAction(); | 3075 if (event->mimeData ()->hasFormat ("text/plain")) |
2816 } | 3076 event->acceptProposedAction (); |
2817 | 3077 } |
2818 void TerminalDisplay::dropEvent(QDropEvent* event) | 3078 |
2819 { | 3079 void |
2820 //KUrl::List urls = KUrl::List::fromMimeData(event->mimeData()); | 3080 TerminalDisplay::dropEvent (QDropEvent * event) |
2821 | 3081 { |
2822 QString dropText; | 3082 //KUrl::List urls = KUrl::List::fromMimeData(event->mimeData()); |
2823 /* | 3083 |
2824 if (!urls.isEmpty()) | 3084 QString dropText; |
2825 { | 3085 /* |
2826 for ( int i = 0 ; i < urls.count() ; i++ ) | 3086 if (!urls.isEmpty()) |
2827 { | 3087 { |
2828 KUrl url = KIO::NetAccess::mostLocalUrl( urls[i] , 0 ); | 3088 for ( int i = 0 ; i < urls.count() ; i++ ) |
2829 QString urlText; | 3089 { |
2830 | 3090 KUrl url = KIO::NetAccess::mostLocalUrl( urls[i] , 0 ); |
2831 if (url.isLocalFile()) | 3091 QString urlText; |
2832 urlText = url.path(); | 3092 |
2833 else | 3093 if (url.isLocalFile()) |
2834 urlText = url.url(); | 3094 urlText = url.path(); |
2835 | 3095 else |
2836 // in future it may be useful to be able to insert file names with drag-and-drop | 3096 urlText = url.url(); |
2837 // without quoting them (this only affects paths with spaces in) | 3097 |
2838 urlText = KShell::quoteArg(urlText); | 3098 // in future it may be useful to be able to insert file names with drag-and-drop |
2839 | 3099 // without quoting them (this only affects paths with spaces in) |
2840 dropText += urlText; | 3100 urlText = KShell::quoteArg(urlText); |
2841 | 3101 |
2842 if ( i != urls.count()-1 ) | 3102 dropText += urlText; |
2843 dropText += ' '; | 3103 |
2844 } | 3104 if ( i != urls.count()-1 ) |
2845 } | 3105 dropText += ' '; |
2846 else | 3106 } |
2847 { | 3107 } |
2848 dropText = event->mimeData()->text(); | 3108 else |
2849 } | 3109 { |
2850 */ | 3110 dropText = event->mimeData()->text(); |
2851 | 3111 } |
2852 if(event->mimeData()->hasFormat("text/plain")) | 3112 */ |
2853 { | 3113 |
2854 emit sendStringToEmu(dropText.toLocal8Bit()); | 3114 if (event->mimeData ()->hasFormat ("text/plain")) |
2855 } | 3115 { |
2856 } | 3116 emit sendStringToEmu (dropText.toLocal8Bit ()); |
2857 | 3117 } |
2858 void TerminalDisplay::doDrag() | 3118 } |
2859 { | 3119 |
2860 dragInfo.state = diDragging; | 3120 void |
2861 dragInfo.dragObject = new QDrag(this); | 3121 TerminalDisplay::doDrag () |
2862 QMimeData *mimeData = new QMimeData; | 3122 { |
2863 mimeData->setText(QApplication::clipboard()->text(QClipboard::Selection)); | 3123 dragInfo.state = diDragging; |
2864 dragInfo.dragObject->setMimeData(mimeData); | 3124 dragInfo.dragObject = new QDrag (this); |
2865 dragInfo.dragObject->start(Qt::CopyAction); | 3125 QMimeData *mimeData = new QMimeData; |
2866 // Don't delete the QTextDrag object. Qt will delete it when it's done with it. | 3126 mimeData->setText (QApplication::clipboard ()-> |
2867 } | 3127 text (QClipboard::Selection)); |
2868 | 3128 dragInfo.dragObject->setMimeData (mimeData); |
2869 void TerminalDisplay::outputSuspended(bool suspended) | 3129 dragInfo.dragObject->start (Qt::CopyAction); |
2870 { | 3130 // Don't delete the QTextDrag object. Qt will delete it when it's done with it. |
2871 //create the label when this function is first called | 3131 } |
2872 if (!_outputSuspendedLabel) | 3132 |
2873 { | 3133 void |
2874 //This label includes a link to an English language website | 3134 TerminalDisplay::outputSuspended (bool suspended) |
2875 //describing the 'flow control' (Xon/Xoff) feature found in almost | 3135 { |
2876 //all terminal emulators. | 3136 //create the label when this function is first called |
2877 //If there isn't a suitable article available in the target language the link | 3137 if (!_outputSuspendedLabel) |
2878 //can simply be removed. | 3138 { |
2879 _outputSuspendedLabel = new QLabel( QString("<qt>Output has been " | 3139 //This label includes a link to an English language website |
2880 "<a href=\"http://en.wikipedia.org/wiki/Flow_control\">suspended</a>" | 3140 //describing the 'flow control' (Xon/Xoff) feature found in almost |
2881 " by pressing Ctrl+S." | 3141 //all terminal emulators. |
2882 " Press <b>Ctrl+Q</b> to resume.</qt>"), | 3142 //If there isn't a suitable article available in the target language the link |
2883 this ); | 3143 //can simply be removed. |
2884 | 3144 _outputSuspendedLabel = new QLabel (QString ("<qt>Output has been " |
2885 QPalette palette(_outputSuspendedLabel->palette()); | 3145 "<a href=\"http://en.wikipedia.org/wiki/Flow_control\">suspended</a>" |
2886 //KColorScheme::adjustBackground(palette,KColorScheme::NeutralBackground); | 3146 " by pressing Ctrl+S." |
2887 _outputSuspendedLabel->setPalette(palette); | 3147 " Press <b>Ctrl+Q</b> to resume.</qt>"), |
2888 _outputSuspendedLabel->setAutoFillBackground(true); | 3148 this); |
2889 _outputSuspendedLabel->setBackgroundRole(QPalette::Base); | 3149 |
2890 _outputSuspendedLabel->setFont(QApplication::font()); | 3150 QPalette palette (_outputSuspendedLabel->palette ()); |
2891 _outputSuspendedLabel->setContentsMargins(5, 5, 5, 5); | 3151 //KColorScheme::adjustBackground(palette,KColorScheme::NeutralBackground); |
2892 | 3152 _outputSuspendedLabel->setPalette (palette); |
2893 //enable activation of "Xon/Xoff" link in label | 3153 _outputSuspendedLabel->setAutoFillBackground (true); |
2894 _outputSuspendedLabel->setTextInteractionFlags(Qt::LinksAccessibleByMouse | | 3154 _outputSuspendedLabel->setBackgroundRole (QPalette::Base); |
2895 Qt::LinksAccessibleByKeyboard); | 3155 _outputSuspendedLabel->setFont (QApplication::font ()); |
2896 _outputSuspendedLabel->setOpenExternalLinks(true); | 3156 _outputSuspendedLabel->setContentsMargins (5, 5, 5, 5); |
2897 _outputSuspendedLabel->setVisible(false); | 3157 |
2898 | 3158 //enable activation of "Xon/Xoff" link in label |
2899 _gridLayout->addWidget(_outputSuspendedLabel); | 3159 _outputSuspendedLabel-> |
2900 _gridLayout->addItem( new QSpacerItem(0,0,QSizePolicy::Expanding, | 3160 setTextInteractionFlags (Qt::LinksAccessibleByMouse | Qt:: |
2901 QSizePolicy::Expanding), | 3161 LinksAccessibleByKeyboard); |
2902 1,0); | 3162 _outputSuspendedLabel->setOpenExternalLinks (true); |
2903 | 3163 _outputSuspendedLabel->setVisible (false); |
2904 } | 3164 |
2905 | 3165 _gridLayout->addWidget (_outputSuspendedLabel); |
2906 _outputSuspendedLabel->setVisible(suspended); | 3166 _gridLayout->addItem (new QSpacerItem (0, 0, QSizePolicy::Expanding, |
2907 } | 3167 QSizePolicy::Expanding), 1, 0); |
2908 | 3168 |
2909 uint TerminalDisplay::lineSpacing() const | 3169 } |
2910 { | 3170 |
2911 return _lineSpacing; | 3171 _outputSuspendedLabel->setVisible (suspended); |
2912 } | 3172 } |
2913 | 3173 |
2914 void TerminalDisplay::setLineSpacing(uint i) | 3174 uint |
2915 { | 3175 TerminalDisplay::lineSpacing () const |
2916 _lineSpacing = i; | 3176 { |
2917 setVTFont(font()); // Trigger an update. | 3177 return _lineSpacing; |
2918 } | 3178 } |
2919 | 3179 |
2920 AutoScrollHandler::AutoScrollHandler(QWidget* parent) | 3180 void |
2921 : QObject(parent) | 3181 TerminalDisplay::setLineSpacing (uint i) |
2922 , _timerId(0) | 3182 { |
2923 { | 3183 _lineSpacing = i; |
2924 //parent->installEventFilter(this); | 3184 setVTFont (font ()); // Trigger an update. |
2925 } | 3185 } |
2926 void AutoScrollHandler::timerEvent(QTimerEvent* event) | 3186 |
2927 { | 3187 AutoScrollHandler::AutoScrollHandler (QWidget * parent):QObject (parent), |
2928 if (event->timerId() != _timerId) | 3188 _timerId (0) |
2929 return; | 3189 { |
2930 | 3190 //parent->installEventFilter(this); |
2931 QMouseEvent mouseEvent( QEvent::MouseMove, | 3191 } |
2932 widget()->mapFromGlobal(QCursor::pos()), | 3192 |
2933 Qt::NoButton, | 3193 void |
2934 Qt::LeftButton, | 3194 AutoScrollHandler::timerEvent (QTimerEvent * event) |
2935 Qt::NoModifier); | 3195 { |
2936 | 3196 if (event->timerId () != _timerId) |
2937 QApplication::sendEvent(widget(),&mouseEvent); | 3197 return; |
2938 } | 3198 |
2939 bool AutoScrollHandler::eventFilter(QObject* watched,QEvent* event) | 3199 QMouseEvent mouseEvent (QEvent::MouseMove, |
2940 { | 3200 widget ()->mapFromGlobal (QCursor::pos ()), |
2941 Q_ASSERT( watched == parent() ); | 3201 Qt::NoButton, Qt::LeftButton, Qt::NoModifier); |
2942 Q_UNUSED( watched ); | 3202 |
2943 | 3203 QApplication::sendEvent (widget (), &mouseEvent); |
2944 QMouseEvent* mouseEvent = (QMouseEvent*)event; | 3204 } |
2945 switch (event->type()) | 3205 |
3206 bool | |
3207 AutoScrollHandler::eventFilter (QObject * watched, QEvent * event) | |
3208 { | |
3209 Q_ASSERT (watched == parent ()); | |
3210 Q_UNUSED (watched); | |
3211 | |
3212 QMouseEvent *mouseEvent = (QMouseEvent *) event; | |
3213 switch (event->type ()) | |
2946 { | 3214 { |
2947 case QEvent::MouseMove: | 3215 case QEvent::MouseMove: |
2948 { | 3216 { |
2949 bool mouseInWidget = widget()->rect().contains(mouseEvent->pos()); | 3217 bool mouseInWidget = widget ()->rect ().contains (mouseEvent->pos ()); |
2950 | 3218 |
2951 if (mouseInWidget) | 3219 if (mouseInWidget) |
2952 { | 3220 { |
2953 if (_timerId) | 3221 if (_timerId) |
2954 killTimer(_timerId); | 3222 killTimer (_timerId); |
2955 _timerId = 0; | 3223 _timerId = 0; |
2956 } | 3224 } |
2957 else | 3225 else |
2958 { | 3226 { |
2959 if (!_timerId && (mouseEvent->buttons() & Qt::LeftButton)) | 3227 if (!_timerId && (mouseEvent->buttons () & Qt::LeftButton)) |
2960 _timerId = startTimer(100); | 3228 _timerId = startTimer (100); |
2961 } | 3229 } |
2962 break; | 3230 break; |
2963 } | 3231 } |
2964 case QEvent::MouseButtonRelease: | 3232 case QEvent::MouseButtonRelease: |
2965 if (_timerId && (mouseEvent->buttons() & ~Qt::LeftButton)) | 3233 if (_timerId && (mouseEvent->buttons () & ~Qt::LeftButton)) |
2966 { | 3234 { |
2967 killTimer(_timerId); | 3235 killTimer (_timerId); |
2968 _timerId = 0; | 3236 _timerId = 0; |
2969 } | 3237 } |
2970 break; | 3238 break; |
2971 default: | 3239 default: |
2972 break; | 3240 break; |
2973 }; | 3241 }; |
2974 | 3242 |
2975 return false; | 3243 return false; |
2976 } | 3244 } |