summaryrefslogtreecommitdiff
Side-by-side diff
Diffstat (more/less context) (show whitespace changes)
-rw-r--r--core/apps/embeddedkonsole/TEWidget.cpp2
1 files changed, 1 insertions, 1 deletions
diff --git a/core/apps/embeddedkonsole/TEWidget.cpp b/core/apps/embeddedkonsole/TEWidget.cpp
index cacc3c4..4c6ea2a 100644
--- a/core/apps/embeddedkonsole/TEWidget.cpp
+++ b/core/apps/embeddedkonsole/TEWidget.cpp
@@ -1,826 +1,826 @@
/* ------------------------------------------------------------------------ */
/* */
/* [TEWidget.C] Terminal Emulation Widget */
/* */
/* ------------------------------------------------------------------------ */
/* */
/* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */
/* */
/* This file is part of Konsole - an X terminal for KDE */
/* */
/* ------------------------------------------------------------------------ */
/* */
/* Ported Konsole to Qt/Embedded */
/* */
/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */
/* */
/* -------------------------------------------------------------------------- */
/*! \class TEWidget
\brief Visible screen contents
This class is responsible to map the `image' of a terminal emulation to the
display. All the dependency of the emulation to a specific GUI or toolkit is
localized here. Further, this widget has no knowledge about being part of an
emulation, it simply work within the terminal emulation framework by exposing
size and key events and by being ordered to show a new image.
<ul>
<li> The internal image has the size of the widget (evtl. rounded up)
<li> The external image used in setImage can have any size.
<li> (internally) the external image is simply copied to the internal
when a setImage happens. During a resizeEvent no painting is done
a paintEvent is expected to follow anyway.
</ul>
\sa TEScreen \sa Emulation
*/
/* FIXME:
- 'image' may also be used uninitialized (it isn't in fact) in resizeEvent
- 'font_a' not used in mouse events
- add destructor
*/
/* TODO
- evtl. be sensitive to `paletteChange' while using default colors.
- set different 'rounding' styles? I.e. have a mode to show clipped chars?
*/
// #include "config.h"
#include "TEWidget.h"
#include "session.h"
#include <qpe/config.h>
#include <qpe/resource.h>
#include <qpe/sound.h>
-#ifdef QWS
+#if !(QT_NO_COP)
#include <qpe/qcopenvelope_qws.h>
#endif
#include <qcursor.h>
#include <qregexp.h>
#include <qpainter.h>
#include <qclipboard.h>
#include <qstyle.h>
#include <qfile.h>
#include <qdragobject.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <signal.h>
#include <assert.h>
// #include "TEWidget.moc"
//#include <kapp.h>
//#include <kcursor.h>
//#include <kurl.h>
//#include <kdebug.h>
//#include <klocale.h>
#define HERE printf("%s(%d): %s\n",__FILE__,__LINE__,__FUNCTION__)
#define HCNT(Name) // { static int cnt = 1; printf("%s(%d): %s %d\n",__FILE__,__LINE__,Name,cnt++); }
#define loc(X,Y) ((Y)*columns+(X))
//FIXME: the rim should normally be 1, 0 only when running in full screen mode.
#define rimX 0 // left/right rim width
#define rimY 0 // top/bottom rim high
#define SCRWIDTH 16 // width of the scrollbar
#define yMouseScroll 1
// scroll increment used when dragging selection at top/bottom of window.
/* ------------------------------------------------------------------------- */
/* */
/* Colors */
/* */
/* ------------------------------------------------------------------------- */
//FIXME: the default color table is in session.C now.
// We need a way to get rid of this one, here.
static const ColorEntry base_color_table[TABLE_COLORS] =
// The following are almost IBM standard color codes, with some slight
// gamma correction for the dim colors to compensate for bright X screens.
// It contains the 8 ansiterm/xterm colors in 2 intensities.
{
// Fixme: could add faint colors here, also.
// normal
ColorEntry(QColor(0x00,0x00,0x00), 0, 0 ), ColorEntry( QColor(0xB2,0xB2,0xB2), 1, 0 ), // Dfore, Dback
ColorEntry(QColor(0x00,0x00,0x00), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0x18), 0, 0 ), // Black, Red
ColorEntry(QColor(0x18,0xB2,0x18), 0, 0 ), ColorEntry( QColor(0xB2,0x68,0x18), 0, 0 ), // Green, Yellow
ColorEntry(QColor(0x18,0x18,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0xB2), 0, 0 ), // Blue, Magenta
ColorEntry(QColor(0x18,0xB2,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0xB2,0xB2), 0, 0 ), // Cyan, White
// intensiv
ColorEntry(QColor(0x00,0x00,0x00), 0, 1 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 1, 0 ),
ColorEntry(QColor(0x68,0x68,0x68), 0, 0 ), ColorEntry( QColor(0xFF,0x54,0x54), 0, 0 ),
ColorEntry(QColor(0x54,0xFF,0x54), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0x54), 0, 0 ),
ColorEntry(QColor(0x54,0x54,0xFF), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0xB2), 0, 0 ),
ColorEntry(QColor(0x54,0xFF,0xFF), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 0, 0 )
};
/* Note that we use ANSI color order (bgr), while IBMPC color order is (rgb)
Code 0 1 2 3 4 5 6 7
----------- ------- ------- ------- ------- ------- ------- ------- -------
ANSI (bgr) Black Red Green Yellow Blue Magenta Cyan White
IBMPC (rgb) Black Blue Green Cyan Red Magenta Yellow White
*/
QColor TEWidget::getDefaultBackColor()
{
return color_table[DEFAULT_BACK_COLOR].color;
}
const ColorEntry* TEWidget::getColorTable() const
{
return color_table;
}
const ColorEntry* TEWidget::getdefaultColorTable() const
{
return base_color_table;
}
const QPixmap *TEWidget::backgroundPixmap()
{
static QPixmap *bg = new QPixmap("~/qpim/main/pics/faded_bg.xpm");
const QPixmap *pm = bg;
return pm;
}
void TEWidget::setColorTable(const ColorEntry table[])
{
for (int i = 0; i < TABLE_COLORS; i++) color_table[i] = table[i];
const QPixmap* pm = backgroundPixmap();
if (!pm) setBackgroundColor(color_table[DEFAULT_BACK_COLOR].color);
update();
}
//FIXME: add backgroundPixmapChanged.
/* ------------------------------------------------------------------------- */
/* */
/* Font */
/* */
/* ------------------------------------------------------------------------- */
/*
The VT100 has 32 special graphical characters. The usual vt100 extended
xterm fonts have these at 0x00..0x1f.
QT's iso mapping leaves 0x00..0x7f without any changes. But the graphicals
come in here as proper unicode characters.
We treat non-iso10646 fonts as VT100 extended and do the requiered mapping
from unicode to 0x00..0x1f. The remaining translation is then left to the
QCodec.
*/
// assert for i in [0..31] : vt100extended(vt100_graphics[i]) == i.
unsigned short vt100_graphics[32] =
{ // 0/8 1/9 2/10 3/11 4/12 5/13 6/14 7/15
0x0020, 0x25C6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0,
0x00b1, 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c,
0xF800, 0xF801, 0x2500, 0xF803, 0xF804, 0x251c, 0x2524, 0x2534,
0x252c, 0x2502, 0x2264, 0x2265, 0x03C0, 0x2260, 0x00A3, 0x00b7
};
static QChar vt100extended(QChar c)
{
switch (c.unicode())
{
case 0x25c6 : return 1;
case 0x2592 : return 2;
case 0x2409 : return 3;
case 0x240c : return 4;
case 0x240d : return 5;
case 0x240a : return 6;
case 0x00b0 : return 7;
case 0x00b1 : return 8;
case 0x2424 : return 9;
case 0x240b : return 10;
case 0x2518 : return 11;
case 0x2510 : return 12;
case 0x250c : return 13;
case 0x2514 : return 14;
case 0x253c : return 15;
case 0xf800 : return 16;
case 0xf801 : return 17;
case 0x2500 : return 18;
case 0xf803 : return 19;
case 0xf804 : return 20;
case 0x251c : return 21;
case 0x2524 : return 22;
case 0x2534 : return 23;
case 0x252c : return 24;
case 0x2502 : return 25;
case 0x2264 : return 26;
case 0x2265 : return 27;
case 0x03c0 : return 28;
case 0x2260 : return 29;
case 0x00a3 : return 30;
case 0x00b7 : return 31;
}
return c;
}
static QChar identicalMap(QChar c)
{
return c;
}
void TEWidget::fontChange(const QFont &)
{
QFontMetrics fm(font());
font_h = fm.height();
font_w = fm.maxWidth();
font_a = fm.ascent();
//printf("font_h: %d\n",font_h);
//printf("font_w: %d\n",font_w);
//printf("font_a: %d\n",font_a);
//printf("charset: %s\n",QFont::encodingName(font().charSet()).ascii());
//printf("rawname: %s\n",font().rawName().ascii());
fontMap =
#if QT_VERSION < 300
strcmp(QFont::encodingName(font().charSet()).ascii(),"iso10646")
? vt100extended
:
#endif
identicalMap;
propagateSize();
update();
}
void TEWidget::setVTFont(const QFont& f)
{
QFrame::setFont(f);
}
QFont TEWidget::getVTFont() {
return font();
}
void TEWidget::setFont(const QFont &)
{
// ignore font change request if not coming from konsole itself
}
/* ------------------------------------------------------------------------- */
/* */
/* Constructor / Destructor */
/* */
/* ------------------------------------------------------------------------- */
TEWidget::TEWidget(QWidget *parent, const char *name) : QFrame(parent,name)
{
#ifndef QT_NO_CLIPBOARD
cb = QApplication::clipboard();
QObject::connect( (QObject*)cb, SIGNAL(dataChanged()),
this, SLOT(onClearSelection()) );
#endif
scrollbar = new QScrollBar(this);
scrollbar->setCursor( arrowCursor );
connect(scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scrollChanged(int)));
hScrollbar = new QScrollBar(this);
hScrollbar->setCursor( arrowCursor );
hScrollbar->setOrientation(QScrollBar::Horizontal);
hScrollbar->setMaximumHeight(16);
connect( hScrollbar, SIGNAL(valueChanged(int)), this, SLOT( hScrollChanged(int)));
Config cfg("Konsole");
cfg.setGroup("ScrollBar");
switch( cfg.readNumEntry("Position",2)){
case 0:
scrollLoc = SCRNONE;
break;
case 1:
scrollLoc = SCRLEFT;
break;
case 2:
scrollLoc = SCRRIGHT;
break;
};
useHorzScroll=cfg.readBoolEntry("HorzScroll",0);
blinkT = new QTimer(this);
connect(blinkT, SIGNAL(timeout()), this, SLOT(blinkEvent()));
// blinking = FALSE;
blinking = TRUE;
resizing = FALSE;
actSel = 0;
image = 0;
lines = 1;
columns = 1;
font_w = 1;
font_h = 1;
font_a = 1;
word_selection_mode = FALSE;
hposition = 0;
vcolumns = 0;
setMouseMarks(TRUE);
setVTFont( QFont("fixed") );
setColorTable(base_color_table); // init color table
qApp->installEventFilter( this ); //FIXME: see below
// KCursor::setAutoHideCursor( this, true );
// Init DnD ////////////////////////////////////////////////////////////////
currentSession = NULL;
// setAcceptDrops(true); // attempt
// m_drop = new QPopupMenu(this);
// m_drop->insertItem( QString("Paste"), 0);
// m_drop->insertItem( QString("cd"), 1);
// connect(m_drop, SIGNAL(activated(int)), SLOT(drop_menu_activated(int)));
// we need focus so that the auto-hide cursor feature works
setFocus();
setFocusPolicy( WheelFocus );
}
//FIXME: make proper destructor
// Here's a start (David)
TEWidget::~TEWidget()
{
qApp->removeEventFilter( this );
if (image) free(image);
}
/* ------------------------------------------------------------------------- */
/* */
/* Display Operations */
/* */
/* ------------------------------------------------------------------------- */
/*!
attributed string draw primitive
*/
void TEWidget::drawAttrStr(QPainter &paint, QRect rect,
QString& str, ca attr, BOOL pm, BOOL clear)
{
if (pm && color_table[attr.b].transparent)
{
paint.setBackgroundMode( TransparentMode );
if (clear) erase(rect);
}
else
{
if (blinking)
paint.fillRect(rect, color_table[attr.b].color);
else
{
paint.setBackgroundMode( OpaqueMode );
paint.setBackgroundColor( color_table[attr.b].color );
}
}
if (color_table[attr.f].bold)
paint.setPen(QColor( 0x8F, 0x00, 0x00 ));
else
paint.setPen(color_table[attr.f].color);
paint.drawText(rect.x(),rect.y()+font_a, str);
if (attr.r & RE_UNDERLINE)
paint.drawLine(rect.left(), rect.y()+font_a+1, rect.right(),rect.y()+font_a+1 );
}
/*!
The image can only be set completely.
The size of the new image may or may not match the size of the widget.
*/
void TEWidget::setImage(const ca* const newimg, int lines, int columns)
{ int y,x,len;
const QPixmap* pm = backgroundPixmap();
QPainter paint;
setUpdatesEnabled(FALSE);
paint.begin( this );
HCNT("setImage");
QPoint tL = contentsRect().topLeft();
int tLx = tL.x();
int tLy = tL.y();
hasBlinker = FALSE;
int cf = -1; // undefined
int cb = -1; // undefined
int cr = -1; // undefined
int lins = QMIN(this->lines, QMAX(0,lines ));
int cols = QMIN(this->columns,QMAX(0,columns));
QChar *disstrU = new QChar[cols];
for (y = 0; y < lins; y++) {
const ca* lcl = &image[y*this->columns];
const ca* const ext = &newimg[y*columns];
if (!resizing) // not while resizing, we're expecting a paintEvent
for (x = 0; x < cols; x++)
{
hasBlinker |= (ext[x].r & RE_BLINK);
if (ext[x] != lcl[x])
{
cr = ext[x].r;
cb = ext[x].b;
if (ext[x].f != cf) cf = ext[x].f;
int lln = cols - x;
disstrU[0] = fontMap(ext[x+0].c);
for (len = 1; len < lln; len++)
{
if (ext[x+len].f != cf || ext[x+len].b != cb || ext[x+len].r != cr ||
ext[x+len] == lcl[x+len] )
break;
disstrU[len] = fontMap(ext[x+len].c);
}
QString unistr(disstrU,len);
drawAttrStr(paint,
QRect(blX+tLx+font_w*x,bY+tLy+font_h*y,font_w*len,font_h),
unistr, ext[x], pm != NULL, true);
x += len - 1;
}
}
// finally, make `image' become `newimg'.
memcpy((void*)lcl,(const void*)ext,cols*sizeof(ca));
}
drawFrame( &paint );
paint.end();
setUpdatesEnabled(TRUE);
if ( hasBlinker && !blinkT->isActive()) blinkT->start(1000); // 1000 ms
if (!hasBlinker && blinkT->isActive()) { blinkT->stop(); blinking = FALSE; }
delete [] disstrU;
}
// paint Event ////////////////////////////////////////////////////
/*!
The difference of this routine vs. the `setImage' is,
that the drawing does not include a difference analysis
between the old and the new image. Instead, the internal
image is used and the painting bound by the PaintEvent box.
*/
void TEWidget::paintEvent( QPaintEvent* pe )
{
//{ static int cnt = 0; printf("paint %d\n",cnt++); }
const QPixmap* pm = backgroundPixmap();
QPainter paint;
setUpdatesEnabled(FALSE);
paint.begin( this );
paint.setBackgroundMode( TransparentMode );
HCNT("paintEvent");
// Note that the actual widget size can be slightly larger
// that the image (the size is truncated towards the smaller
// number of characters in `resizeEvent'. The paint rectangle
// can thus be larger than the image, but less then the size
// of one character.
QRect rect = pe->rect().intersect(contentsRect());
QPoint tL = contentsRect().topLeft();
int tLx = tL.x();
int tLy = tL.y();
int lux = QMIN(columns-1, QMAX(0,(rect.left() - tLx - blX ) / font_w));
int luy = QMIN(lines-1, QMAX(0,(rect.top() - tLy - bY ) / font_h));
int rlx = QMIN(columns-1, QMAX(0,(rect.right() - tLx - blX ) / font_w));
int rly = QMIN(lines-1, QMAX(0,(rect.bottom() - tLy - bY ) / font_h));
/*
printf("paintEvent: %d..%d, %d..%d (%d..%d, %d..%d)\n",lux,rlx,luy,rly,
rect.left(), rect.right(), rect.top(), rect.bottom());
*/
// if (pm != NULL && color_table[image->b].transparent)
// erase(rect);
// BL: I have no idea why we need this, and it breaks the refresh.
QChar *disstrU = new QChar[columns];
for (int y = luy; y <= rly; y++)
for (int x = lux; x <= rlx; x++)
{
int len = 1;
disstrU[0] = fontMap(image[loc(x,y)].c);
int cf = image[loc(x,y)].f;
int cb = image[loc(x,y)].b;
int cr = image[loc(x,y)].r;
while (x+len <= rlx &&
image[loc(x+len,y)].f == cf &&
image[loc(x+len,y)].b == cb &&
image[loc(x+len,y)].r == cr )
{
disstrU[len] = fontMap(image[loc(x+len,y)].c);
len += 1;
}
QString unistr(disstrU,len);
drawAttrStr(paint,
QRect(blX+tLx+font_w*x,bY+tLy+font_h*y,font_w*len,font_h),
unistr, image[loc(x,y)], pm != NULL, false);
x += len - 1;
}
delete [] disstrU;
drawFrame( &paint );
paint.end();
setUpdatesEnabled(TRUE);
}
void TEWidget::blinkEvent()
{
blinking = !blinking;
repaint(FALSE);
}
/* ------------------------------------------------------------------------- */
/* */
/* Resizing */
/* */
/* ------------------------------------------------------------------------- */
void TEWidget::resizeEvent(QResizeEvent* ev)
{
// printf("resize: %d,%d\n",ev->size().width(),ev->size().height());
//printf("approx: %d,%d\n",ev->size().width()/font_w,ev->size().height()/font_h);
//printf("leaves: %d,%d\n",ev->size().width()%font_w,ev->size().height()%font_h);
//printf("curren: %d,%d\n",width(),height());
HCNT("resizeEvent");
// see comment in `paintEvent' concerning the rounding.
//FIXME: could make a routine here; check width(),height()
assert(ev->size().width() == width());
assert(ev->size().height() == height());
propagateSize();
}
void TEWidget::propagateSize()
{
ca* oldimg = image;
int oldlin = lines;
int oldcol = columns;
makeImage();
// we copy the old image to reduce flicker
int lins = QMIN(oldlin,lines);
int cols = QMIN(oldcol,columns);
if (oldimg)
{
for (int lin = 0; lin < lins; lin++)
memcpy((void*)&image[columns*lin],
(void*)&oldimg[oldcol*lin],cols*sizeof(ca));
free(oldimg); //FIXME: try new,delete
}
else
clearImage();
//NOTE: control flows from the back through the chest right into the eye.
// `emu' will call back via `setImage'.
resizing = TRUE;
emit changedImageSizeSignal(lines, columns); // expose resizeEvent
resizing = FALSE;
}
/* ------------------------------------------------------------------------- */
/* */
/* Scrollbar */
/* */
/* ------------------------------------------------------------------------- */
void TEWidget::scrollChanged(int) {
emit changedHistoryCursor(scrollbar->value()); //expose
}
void TEWidget::hScrollChanged(int loc) {
hposition = loc;
propagateSize();
update();
// emit changedHorzCursor( hScrollbar->value()); //expose
}
void TEWidget::setScroll(int cursor, int slines)
{
disconnect(scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scrollChanged(int)));
scrollbar->setRange(0,slines);
scrollbar->setSteps(1,lines);
scrollbar->setValue(cursor);
connect(scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scrollChanged(int)));
}
void TEWidget::setScrollbarLocation(int loc)
{
if (scrollLoc == loc) return; // quickly
scrollLoc = loc;
propagateSize();
update();
}
/* ------------------------------------------------------------------------- */
/* */
/* Mouse */
/* */
/* ------------------------------------------------------------------------- */
/*!
Three different operations can be performed using the mouse, and the
routines in this section serve all of them:
1) The press/release events are exposed to the application
2) Marking (press and move left button) and Pasting (press middle button)
3) The right mouse button is used from the configuration menu
NOTE: During the marking process we attempt to keep the cursor within
the bounds of the text as being displayed by setting the mouse position
whenever the mouse has left the text area.
Two reasons to do so:
1) QT does not allow the `grabMouse' to confine-to the TEWidget.
Thus a `XGrapPointer' would have to be used instead.
2) Even if so, this would not help too much, since the text area
of the TEWidget is normally not identical with it's bounds.
The disadvantage of the current handling is, that the mouse can visibly
leave the bounds of the widget and is then moved back. Because of the
current construction, and the reasons mentioned above, we cannot do better
without changing the overall construction.
*/
/*!
*/
void TEWidget::mousePressEvent(QMouseEvent* ev)
{
//printf("press [%d,%d] %d\n",ev->x()/font_w,ev->y()/font_h,ev->button());
if ( !contentsRect().contains(ev->pos()) ) return;
QPoint tL = contentsRect().topLeft();
int tLx = tL.x();
int tLy = tL.y();
word_selection_mode = FALSE;
//printf("press top left [%d,%d] by=%d\n",tLx,tLy, bY);
if ( ev->button() == LeftButton)
{
QPoint pos = QPoint((ev->x()-tLx-blX)/font_w,(ev->y()-tLy-bY)/font_h);
if ( ev->state() & ControlButton ) preserve_line_breaks = FALSE ;
if (mouse_marks || (ev->state() & ShiftButton))
{
emit clearSelectionSignal();
iPntSel = pntSel = pos;
actSel = 1; // left mouse button pressed but nothing selected yet.
grabMouse( /*crossCursor*/ ); // handle with care!
}
else
{
emit mouseSignal( 0, pos.x() + 1, pos.y() + 1 ); // left button
}
}
if ( ev->button() == MidButton )
{
emitSelection();
}
if ( ev->button() == RightButton ) // Configure
{
emit configureRequest( this, ev->state()&(ShiftButton|ControlButton), ev->x(), ev->y() );
}
}
void TEWidget::mouseMoveEvent(QMouseEvent* ev)
{
// for auto-hiding the cursor, we need mouseTracking
if (ev->state() == NoButton ) return;
if (actSel == 0) return;
// don't extend selection while pasting
if (ev->state() & MidButton) return;
//if ( !contentsRect().contains(ev->pos()) ) return;
QPoint tL = contentsRect().topLeft();
int tLx = tL.x();
int tLy = tL.y();
int scroll = scrollbar->value();
// int hScroll = hScrollbar->value();
// we're in the process of moving the mouse with the left button pressed
// the mouse cursor will kept catched within the bounds of the text in
// this widget.
// Adjust position within text area bounds. See FIXME above.
QPoint pos = ev->pos();
if ( pos.x() < tLx+blX ) pos.setX( tLx+blX );
if ( pos.x() > tLx+blX+columns*font_w-1 ) pos.setX( tLx+blX+columns*font_w );
if ( pos.y() < tLy+bY ) pos.setY( tLy+bY );
if ( pos.y() > tLy+bY+lines*font_h-1 ) pos.setY( tLy+bY+lines*font_h-1 );
// check if we produce a mouse move event by this
if ( pos != ev->pos() ) cursor().setPos(mapToGlobal(pos));
if ( pos.y() == tLy+bY+lines*font_h-1 )
{
scrollbar->setValue(scrollbar->value()+yMouseScroll); // scrollforward
}
if ( pos.y() == tLy+bY )
{
scrollbar->setValue(scrollbar->value()-yMouseScroll); // scrollback
}
QPoint here = QPoint((pos.x()-tLx-blX)/font_w,(pos.y()-tLy-bY)/font_h);
QPoint ohere;
bool swapping = FALSE;
if ( word_selection_mode )
{
// Extend to word boundaries
int i;
int selClass;
bool left_not_right = ( here.y() < iPntSel.y() ||
here.y() == iPntSel.y() && here.x() < iPntSel.x() );
bool old_left_not_right = ( pntSel.y() < iPntSel.y() ||
pntSel.y() == iPntSel.y() && pntSel.x() < iPntSel.x() );
swapping = left_not_right != old_left_not_right;
// Find left (left_not_right ? from here : from start)
QPoint left = left_not_right ? here : iPntSel;
i = loc(left.x(),left.y());
selClass = charClass(image[i].c);
while ( left.x() > 0 && charClass(image[i-1].c) == selClass )
{ i--; left.rx()--; }
// Find left (left_not_right ? from start : from here)
QPoint right = left_not_right ? iPntSel : here;
i = loc(right.x(),right.y());
selClass = charClass(image[i].c);
while ( right.x() < columns-1 && charClass(image[i+1].c) == selClass )
{ i++; right.rx()++; }
// Pick which is start (ohere) and which is extension (here)
if ( left_not_right )
{
here = left; ohere = right;
}
else
{
here = right; ohere = left;
}
}
if (here == pntSel && scroll == scrollbar->value()) return; // not moved
if ( word_selection_mode ) {
if ( actSel < 2 || swapping ) {
emit beginSelectionSignal( ohere.x(), ohere.y() );
}
} else if ( actSel < 2 ) {
emit beginSelectionSignal( pntSel.x(), pntSel.y() );
}
actSel = 2; // within selection
pntSel = here;
emit extendSelectionSignal( here.x(), here.y() );
}
void TEWidget::mouseReleaseEvent(QMouseEvent* ev)
{
//printf("release [%d,%d] %d\n",ev->x()/font_w,ev->y()/font_h,ev->button());
if ( ev->button() == LeftButton)
{
if ( actSel > 1 ) emit endSelectionSignal(preserve_line_breaks);
preserve_line_breaks = TRUE;
actSel = 0;
//FIXME: emits a release event even if the mouse is
// outside the range. The procedure used in `mouseMoveEvent'
// applies here, too.
QPoint tL = contentsRect().topLeft();
int tLx = tL.x();
int tLy = tL.y();
if (!mouse_marks && !(ev->state() & ShiftButton))
emit mouseSignal( 3, // release
(ev->x()-tLx-blX)/font_w + 1,
(ev->y()-tLy-bY)/font_h + 1 );
releaseMouse();
}
}