First new implementation of "tap" and some enhancements/bugfixes/refactoring

- Layer icons can be obtained now
- Icon dimension is arbitrary
- Scaling icons for layer list
- More robust event handling in case of pop-up menus
  (selector)
- "Tap" will noe pop up a menu with all layers below the cursor.
  When selected, the current layer is switched.
This commit is contained in:
Matthias Koefferlein 2020-08-03 10:34:16 +02:00
parent f810eae7a0
commit 1887fd715a
12 changed files with 470 additions and 269 deletions

View File

@ -30,7 +30,11 @@
#include "tlExceptions.h"
#include "layLayoutView.h"
#include "layDialogs.h"
#include "laySelector.h"
#include "layCellSelectionForm.h"
#include "layFinder.h"
#include "layLayerProperties.h"
#include "layLayerTreeModel.h"
#include "tlProgress.h"
#include "edtPlugin.h"
#include "edtMainService.h"
@ -41,6 +45,8 @@
#include "edtEditorOptionsPages.h"
#include <QMessageBox>
#include <QFontInfo>
#include <QWidgetAction>
namespace edt
{
@ -1941,21 +1947,60 @@ MainService::cm_make_array ()
void
MainService::cm_tap ()
{
tl_assert (view ()->is_editable ());
check_no_guiding_shapes ();
if (! view ()->view_object_widget ()->mouse_in_window ()) {
return;
}
std::vector<edt::Service *> edt_services = view ()->get_plugins <edt::Service> ();
lay::ShapeFinder finder (true /*point mode*/, false /*all hierarchy levels*/, db::ShapeIterator::All, 0);
// get (common) cellview index of the selected shapes
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
for (edt::Service::obj_iterator s = (*es)->selection ().begin (); s != (*es)->selection ().end (); ++s) {
const lay::CellView &cv = view ()->cellview (s->cv_index ());
if (cv.is_valid () && ! s->is_cell_inst ()) {
view ()->set_current_layer (s->cv_index (), cv->layout ().get_properties (s->layer ()));
return;
}
// capture all objects in point mode (default: capture one only)
finder.set_catch_all (true);
// go through all visible layers of all cellviews
db::DPoint pt = view ()->view_object_widget ()->mouse_position_um ();
finder.find (view (), db::DBox (pt, pt));
std::set<std::pair<unsigned int, unsigned int> > layers_in_selection;
for (lay::ShapeFinder::iterator f = finder.begin (); f != finder.end (); ++f) {
// ignore guiding shapes
if (f->layer () != view ()->cellview (f->cv_index ())->layout ().guiding_shape_layer ()) {
layers_in_selection.insert (std::make_pair (f->cv_index (), f->layer ()));
}
}
std::vector<lay::LayerPropertiesConstIterator> tapped_layers;
for (lay::LayerPropertiesConstIterator lp = view ()->begin_layers (view ()->current_layer_list ()); ! lp.at_end (); ++lp) {
const lay::LayerPropertiesNode *ln = lp.operator-> ();
if (layers_in_selection.find (std::make_pair ((unsigned int) ln->cellview_index (), (unsigned int) ln->layer_index ())) != layers_in_selection.end ()) {
tapped_layers.push_back (lp);
}
}
if (tapped_layers.empty ()) {
return;
}
// List the layers under the cursor as pop up a menu
std::auto_ptr<QMenu> menu (new QMenu (view ()));
menu->show ();
int icon_size = menu->style ()->pixelMetric (QStyle::PM_ButtonIconSize);
QPoint mp = view ()->view_object_widget ()->mapToGlobal (view ()->view_object_widget ()->mouse_position ());
for (std::vector<lay::LayerPropertiesConstIterator>::const_iterator l = tapped_layers.begin (); l != tapped_layers.end (); ++l) {
QAction *a = menu->addAction (lay::LayerTreeModel::icon_for_layer (*l, view (), icon_size, icon_size, 0, true), tl::to_qstring ((*l)->source (true).to_string ()));
a->setData (int (l - tapped_layers.begin ()));
}
QAction *action = menu->exec (mp);
if (action) {
int index = action->data ().toInt ();
lay::LayerPropertiesConstIterator iter = tapped_layers [index];
view ()->set_current_layer (iter);
}
}
void

View File

@ -380,7 +380,38 @@ Bitmap::fill (unsigned int y, unsigned int x1, unsigned int x2)
}
}
struct PosCompareF
void
Bitmap::clear (unsigned int y, unsigned int x1, unsigned int x2)
{
unsigned int b1 = x1 / 32;
uint32_t *sl = scanline (y);
sl += b1;
unsigned int b = x2 / 32 - b1;
if (b == 0) {
*sl &= ~masks [x2 % 32] | masks [x1 % 32];
} else if (b > 0) {
*sl++ &= masks [x1 % 32];
while (b > 1) {
*sl++ = 0;
b--;
}
unsigned int m = masks [x2 % 32];
// Hint: if x2==width and width%32==0, sl must not be accessed. This is guaranteed by
// checking if m != 0.
if (m) {
*sl &= ~m;
}
}
}
struct PosCompareF
{
bool operator() (const RenderEdge &a, const RenderEdge &b) const
{

View File

@ -246,6 +246,17 @@ public:
*/
void fill (unsigned int y, unsigned int x1, unsigned int x2);
/**
* @brief Clears the given part of the scanline
*
* Same as fill(), but resets the bits.
*
* @param y The scanline
* @param x1 The start coordinate
* @param x2 The end coordinate
*/
void clear (unsigned int y, unsigned int x1, unsigned int x2);
/**
* @brief Merges the "from" bitmap into this
*

View File

@ -62,7 +62,7 @@ static int inst_point_sel_tests = 10000;
Finder::Finder (bool point_mode, bool top_level_sel)
: m_min_level (0), m_max_level (0),
mp_layout (0), mp_view (0), m_cv_index (0), m_point_mode (point_mode), m_top_level_sel (top_level_sel)
mp_layout (0), mp_view (0), m_cv_index (0), m_point_mode (point_mode), m_catch_all (false), m_top_level_sel (top_level_sel)
{
m_distance = std::numeric_limits<double>::max ();
}
@ -558,41 +558,32 @@ ShapeFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const
if (match) {
lay::ObjectInstPath found;
found.set_cv_index (m_cv_index);
found.set_topcell (m_topcell);
found.assign_path (path ().begin (), path ().end ());
found.set_layer (*l);
found.set_shape (*shape);
if (mp_excludes) {
// with an exclude list first create the selection item so we can check
// if it's part of the exclude set.
lay::ObjectInstPath found;
found.set_cv_index (m_cv_index);
found.set_topcell (m_topcell);
found.assign_path (path ().begin (), path ().end ());
found.set_layer (*l);
found.set_shape (*shape);
// in point mode just store the found object that has the least "distance" and is
// not in the exclude set
if (mp_excludes->find (found) == mp_excludes->end () && closer (d)) {
match = (mp_excludes->find (found) == mp_excludes->end ());
if (m_founds.empty ()) {
m_founds.push_back (found);
} else {
m_founds.front () = found;
}
}
}
} else if (closer (d)) {
if (match && (catch_all () || closer (d))) {
// in point mode just store that found that has the least "distance"
if (m_founds.empty ()) {
m_founds.push_back (lay::ObjectInstPath ());
if (m_founds.empty () || catch_all ()) {
m_founds.push_back (found);
}
m_founds.back ().set_cv_index (m_cv_index);
m_founds.back ().set_topcell (m_topcell);
m_founds.back ().assign_path (path ().begin (), path ().end ());
m_founds.back ().set_layer (*l);
m_founds.back ().set_shape (*shape);
m_founds.back () = found;
}
@ -848,52 +839,38 @@ InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const d
if (match) {
lay::ObjectInstPath found;
found.set_cv_index (m_cv_index);
found.set_topcell (m_topcell);
found.assign_path (path ().begin (), path ().end ());
// add the selected instance as the last element of the path
db::InstElement el;
el.inst_ptr = *inst;
if (! m_full_arrays) {
el.array_inst = p;
}
found.add_path (el);
if (mp_excludes) {
// with an exclude list first create the selection item so we can check
// if it's part of the exclude set.
lay::ObjectInstPath found;
found.set_cv_index (m_cv_index);
found.set_topcell (m_topcell);
found.assign_path (path ().begin (), path ().end ());
// add the selected instance as the last element of the path
db::InstElement el;
el.inst_ptr = *inst;
if (! m_full_arrays) {
el.array_inst = p;
}
found.add_path (el);
// in point mode just store the found object that has the least "distance" and is
// not in the exclude set
if (mp_excludes->find (found) == mp_excludes->end () && closer (d)) {
if (m_founds.empty ()) {
m_founds.push_back (found);
} else {
m_founds.front () = found;
}
}
match = (mp_excludes->find (found) == mp_excludes->end ());
} else if (closer (d)) {
}
if (match && (catch_all () || closer (d))) {
// in point mode just store that found that has the least "distance"
if (m_founds.empty ()) {
if (m_founds.empty () || catch_all ()) {
m_founds.push_back (lay::ObjectInstPath ());
}
m_founds.back ().set_cv_index (m_cv_index);
m_founds.back ().set_topcell (m_topcell);
m_founds.back ().assign_path (path ().begin (), path ().end ());
// add the selected instance as the last element of the path
db::InstElement el;
el.inst_ptr = *inst;
if (! m_full_arrays) {
el.array_inst = p;
}
m_founds.back ().add_path (el);
m_founds.back () = found;
}

View File

@ -58,13 +58,42 @@ public:
*
* The point_mode is true, if the finder is supposed to operate in "point mode".
* In point mode, the center of the search region is the reference point. In
* non-point mode, every relevant found inside the search region should be
* recorded.
* non-point mode, every relevant found inside the search region will be
* recorded (also see point_mode method).
* The base class implementation just stores this flag and provides a read
* accessor with the point_mode () method.
*/
Finder (bool point_mode, bool top_level_sel);
/**
* @brief Gets a flag indicating whether point mode is enabled
* If point mode is enabled in the constructor, the first will check for objects overlapping the
* point (rather than being inside the box) and by default select a single object only.
* See also "set_catch_all".
*/
bool point_mode () const
{
return m_point_mode;
}
/**
* @brief Gets a flag indicating the capture all founds even in point mode
*/
bool catch_all () const
{
return m_catch_all;
}
/**
* @brief Sets a flag indicating the capture all founds even in point mode
* By default, in point mode only the closest found is returned. To catch all
* founds in point mode too, set this flag to true.
*/
void set_catch_all (bool f)
{
m_catch_all = f;
}
/**
* @brief Destructor (just provided to please the compiler)
*/
@ -87,11 +116,6 @@ protected:
return m_layers;
}
bool point_mode () const
{
return m_point_mode;
}
const std::vector<db::InstElement> &path () const
{
return m_path;
@ -166,6 +190,7 @@ private:
std::vector<int> m_layers;
double m_distance;
bool m_point_mode;
bool m_catch_all;
bool m_top_level_sel;
db::box_convert <db::CellInst> m_box_convert;
db::box_convert <db::Cell> m_cell_box_convert;

View File

@ -60,36 +60,6 @@
namespace lay
{
// --------------------------------------------------------------------
// LCPTreeItemDelegate declaration & implementation
/**
* @brief A layer tree widget helper class
*
* A specialization of the ItemDelegate that bypasses the computation
* of sizeHint and returns the pixmap's size directly for higher
* performance.
*/
class LCPItemDelegate : public QItemDelegate
{
public:
LCPItemDelegate (QWidget *parent)
: QItemDelegate (parent)
{ }
private:
virtual QSize
sizeHint (const QStyleOptionViewItem &style, const QModelIndex &index) const
{
if (index.column () == 0) {
return QSize (40, 16);
} else {
return QItemDelegate::sizeHint (style, index);
}
}
};
// --------------------------------------------------------------------
// LCPTreeWidget declaration & implementation
@ -98,7 +68,6 @@ LCPTreeWidget::LCPTreeWidget (QWidget *parent, lay::LayerTreeModel *model, const
{
setObjectName (QString::fromUtf8 (name));
setModel (model);
setItemDelegate (new LCPItemDelegate (this));
#if QT_VERSION >= 0x040200
setAllColumnsShowFocus (true);
#endif
@ -326,7 +295,10 @@ LayerControlPanel::LayerControlPanel (lay::LayoutView *view, db::Manager *manage
mp_model = new lay::LayerTreeModel (this, view);
mp_layer_list = new LCPTreeWidget (this, mp_model, "layer_tree");
mp_layer_list->setUniformRowHeights (true);
mp_model->set_font (mp_layer_list->font ());
mp_layer_list->setIconSize (mp_model->icon_size ());
/*
* At least with Qt 4.2.x setting uniform row heights has a strange side effect:
* If a range is selected and the first selection is scrolled out of view, the
@ -343,7 +315,6 @@ LayerControlPanel::LayerControlPanel (lay::LayoutView *view, db::Manager *manage
mp_layer_list->header ()->hide ();
mp_layer_list->setSelectionMode (QTreeView::ExtendedSelection);
mp_layer_list->setRootIsDecorated (false);
mp_layer_list->setIconSize (QSize (32, 16));
// Custom resize mode makes the columns as narrow as possible
#if QT_VERSION >= 0x050000
mp_layer_list->header ()->setSectionResizeMode (QHeaderView::ResizeToContents);

View File

@ -32,6 +32,7 @@
#include <QTreeView>
#include <QModelIndex>
#include <QString>
#include <QFontInfo>
#include <string.h>
@ -558,6 +559,161 @@ LayerTreeModel::empty_within_view_predicate (const QModelIndex &index) const
}
}
LAYBASIC_PUBLIC
QIcon
LayerTreeModel::icon_for_layer (const lay::LayerPropertiesConstIterator &iter, lay::LayoutView *view, unsigned int w, unsigned int h, unsigned int di_off, bool no_state)
{
h = std::max ((unsigned int) 16, h);
w = std::max ((unsigned int) 16, w);
lay::color_t def_color = 0x808080;
lay::color_t fill_color = iter->has_fill_color (true) ? iter->eff_fill_color (true) : def_color;
lay::color_t frame_color = iter->has_frame_color (true) ? iter->eff_frame_color (true) : def_color;
QImage image (w, h, QImage::Format_ARGB32);
image.fill (view->background_color ().rgb ());
// upper scanline is a dummy one
uint32_t *sl0 = (uint32_t *) image.scanLine (0);
uint32_t transparent = QColor (Qt::transparent).rgba ();
for (size_t i = 0; i < w; ++i) {
*sl0++ = transparent;
}
// TODO: adjust the resolution according to the oversampling mode
lay::Bitmap fill (w, h, 1.0);
lay::Bitmap frame (w, h, 1.0);
lay::Bitmap text (w, h, 1.0);
lay::Bitmap vertex (w, h, 1.0);
unsigned int wp = w - 1;
if (! no_state && ! iter->visible (true)) {
wp = w / 4;
// Show the arrow if it is invisible also locally.
if (! iter->visible (false)) {
unsigned int aw = h / 4;
unsigned int ap = w / 2 - 1;
for (unsigned int i = 0; i <= aw; ++i) {
text.fill (h / 2 - 1 - i, ap, ap + aw - i + 1);
text.fill (h / 2 - 1 + i, ap, ap + aw - i + 1);
}
}
}
if (! no_state && view->no_stipples ()) {
// Show a partial stipple pattern only for "no stipple" mode
for (unsigned int i = 1; i < h - 2; ++i) {
fill.fill (i, w - 1 - w / 4, w);
}
} else {
for (unsigned int i = 1; i < h - 2; ++i) {
fill.fill (i, w - 1 - wp, w);
}
}
int lw = iter->width (true);
if (lw < 0) {
// default line width is 0 for parents and 1 for leafs
lw = iter->has_children () ? 0 : 1;
}
int p0 = lw / 2;
p0 = std::max (0, std::min (int (w / 4 - 1), p0));
int p1 = (lw - 1) / 2;
p1 = std::max (0, std::min (int (w / 4 - 1), p1));
int p0x = p0, p1x = p1;
unsigned int ddx = 0;
unsigned int ddy = h - 2 - p1 - p0;
if (iter->xfill (true)) {
ddx = wp - p0 - p1 - 1;
}
unsigned int d = ddx / 2;
frame.fill (p0, w - 1 - (wp - p1), w);
frame.fill (h - 2 - p1, w - 1 - (wp - p1), w);
for (unsigned int i = p0; i < h - 2; ++i) {
frame.fill (i, w - 1 - p0, w - p0);
frame.fill (i, w - 1 - (wp - p1), w - (wp - p1));
frame.fill (i, w - 1 - p0x, w - p0x);
frame.fill (i, w - 1 - (wp - p1x), w - (wp - p1x));
while (d < ddx) {
d += ddy;
frame.fill (i, w - 1 - p0x, w - p0x);
frame.fill (i, w - 1 - (wp - p1x), w - (wp - p1x));
++p0x;
++p1x;
}
if (d >= ddx) {
d -= ddx;
}
}
if (! no_state && ! iter->valid (true)) {
unsigned int bp = w - 1 - ((w * 7) / 8 - 1);
unsigned int be = bp + h / 2;
unsigned int bw = h / 4 - 1;
unsigned int by = h / 2 - 1;
for (unsigned int i = 0; i < bw + 2; ++i) {
fill.clear (by - i, bp - 1, be);
fill.clear (by + i, bp - 1, be);
}
for (unsigned int i = 0; i < bw; ++i) {
text.fill (by - i, bp + bw - i - 1, bp + bw - i + 1);
text.fill (by - i - 1, bp + bw - i - 1, bp + bw - i + 1);
text.fill (by - i, bp + bw + i, bp + bw + i + 2);
text.fill (by - i - 1, bp + bw + i, bp + bw + i + 2);
text.fill (by + i, bp + bw - i - 1, bp + bw - i + 1);
text.fill (by + i + 1, bp + bw - i - 1, bp + bw - i + 1);
text.fill (by + i, bp + bw + i, bp + bw + i + 2);
text.fill (by + i + 1, bp + bw + i, bp + bw + i + 2);
}
}
vertex.fill (h / 2 - 1, w - 1 - wp / 2, w - wp / 2);
lay::ViewOp::Mode mode = lay::ViewOp::Copy;
// create fill
single_bitmap_to_image (lay::ViewOp (fill_color, mode, 0, iter->eff_dither_pattern (true), di_off), fill, &image, view->dither_pattern (), view->line_styles (), w, h);
// create frame
if (lw == 0) {
single_bitmap_to_image (lay::ViewOp (frame_color, mode, 0 /*solid line*/, 2 /*dotted*/, 0), frame, &image, view->dither_pattern (), view->line_styles (), w, h);
} else {
single_bitmap_to_image (lay::ViewOp (frame_color, mode, iter->eff_line_style (true), 0, 0, lay::ViewOp::Rect, lw), frame, &image, view->dither_pattern (), view->line_styles (), w, h);
}
// create text
single_bitmap_to_image (lay::ViewOp (frame_color, mode, 0, 0, 0), text, &image, view->dither_pattern (), view->line_styles (), w, h);
// create vertex
single_bitmap_to_image (lay::ViewOp (frame_color, mode, 0, 0, 0, lay::ViewOp::Cross, iter->marked (true) ? 9/*mark size*/ : 0), vertex, &image, view->dither_pattern (), view->line_styles (), w, h);
QPixmap pixmap = QPixmap::fromImage (image); // Qt 4.6.0 workaround
return QIcon (pixmap);
}
QSize
LayerTreeModel::icon_size () const
{
unsigned int is = ((QFontInfo (m_font).pixelSize () + 15) / 16) * 16;
return QSize (is * 2, is);
}
QVariant
LayerTreeModel::data (const QModelIndex &index, int role) const
{
@ -568,6 +724,16 @@ LayerTreeModel::data (const QModelIndex &index, int role) const
return QVariant ();
} else if (role == Qt::SizeHintRole) {
if (index.column () == 0) {
// NOTE: for some reason, the widget clips the icon when inside a tree and needs a some what bigger width ..
QSize is = icon_size ();
return QVariant (is + QSize (is.width () / 4, 0));
} else {
return QVariant ();
}
} else if (role == Qt::DisplayRole || role == Qt::EditRole) {
if (index.column () == 1) {
@ -593,142 +759,10 @@ LayerTreeModel::data (const QModelIndex &index, int role) const
}
}
unsigned int w = 32;
unsigned int h = 16;
QSize is = icon_size ();
if (animate_visible) {
lay::color_t def_color = 0x808080;
lay::color_t fill_color = iter->has_fill_color (true) ? iter->eff_fill_color (true) : def_color;
lay::color_t frame_color = iter->has_frame_color (true) ? iter->eff_frame_color (true) : def_color;
QImage image (w, h, QImage::Format_RGB32);
image.fill (m_background_color.rgb ());
// TODO: adjust the resolution according to the oversampling mode
lay::Bitmap fill (w, h, 1.0);
lay::Bitmap frame (w, h, 1.0);
lay::Bitmap text (w, h, 1.0);
lay::Bitmap vertex (w, h, 1.0);
unsigned int mask_w = 31;
unsigned int mask_all = 0xfffffffe;
unsigned int mask_left = 0x80000000;
unsigned int mask_right = 0x00000002;
unsigned int mask_center = 0x00010000;
if (! iter->visible (true)) {
mask_w = 8;
mask_all = 0xff800000;
mask_left = 0x80000000;
mask_right = 0x00800000;
mask_center = 0x08000000;
// Show the arrow if it is invisible also locally.
if (! iter->visible (false)) {
text.scanline (4) [0] = 0x00008000 << 1;
text.scanline (5) [0] = 0x00018000 << 1;
text.scanline (6) [0] = 0x00038000 << 1;
text.scanline (7) [0] = 0x00078000 << 1;
text.scanline (8) [0] = 0x00038000 << 1;
text.scanline (9) [0] = 0x00018000 << 1;
text.scanline (10) [0] = 0x00008000 << 1;
}
}
if (mp_view->no_stipples ()) {
// Show a partial stipple pattern only for "no stipple" mode
for (unsigned int i = 1; i < h - 2; ++i) {
fill.scanline (i) [0] = 0xff800000;
}
} else {
for (unsigned int i = 1; i < h - 2; ++i) {
fill.scanline (i) [0] = mask_all;
}
}
int lw = iter->width (true);
if (lw < 0) {
// default line width is 0 for parents and 1 for leafs
lw = iter->has_children () ? 0 : 1;
}
int p0 = lw / 2;
int p1 = (lw - 1) / 2;
if (p0 < 0) {
p0 = 0;
} else if (p0 > 7) {
p0 = 7;
}
if (p1 < 0) {
p1 = 0;
} else if (p1 > 7) {
p1 = 7;
}
int p0x = p0, p1x = p1;
unsigned int ddx = 0;
unsigned int ddy = h - 2 - p1 - p0;
if (iter->xfill (true)) {
ddx = mask_w - p0 - p1 - 1;
}
unsigned int d = ddx / 2;
frame.scanline (p0) [0] = mask_all << p1;
for (unsigned int i = p0; i < h - 2; ++i) {
frame.scanline (i) [0] |= (mask_left >> p0) | (mask_right << p1);
frame.scanline (i) [0] |= (mask_left >> p0x) | (mask_right << p1x);
while (d < ddx) {
d += ddy;
frame.scanline (i) [0] |= (mask_left >> p0x) | (mask_right << p1x);
++p0x;
++p1x;
}
if (d >= ddx) {
d -= ddx;
}
}
frame.scanline (h - 2 - p1) [0] = mask_all << p1;
if (! iter->valid (true)) {
text.scanline (4) [0] |= 0x00000c60;
text.scanline (5) [0] |= 0x00000ee0;
text.scanline (6) [0] |= 0x000007c0;
text.scanline (7) [0] |= 0x00000380;
text.scanline (8) [0] |= 0x000007c0;
text.scanline (9) [0] |= 0x00000ee0;
text.scanline (10) [0] |= 0x00000c60;
for (unsigned int i = 3; i < 12; ++i) {
fill.scanline (i) [0] &= ~0x00001ff0;
frame.scanline (i) [0] &= ~0x00001ff0;
}
}
vertex.scanline (h / 2 - 1) [0] = mask_center;
lay::ViewOp::Mode mode = lay::ViewOp::Copy;
// create fill
single_bitmap_to_image (lay::ViewOp (fill_color, mode, 0, iter->eff_dither_pattern (true), di_off), fill, &image, mp_view->dither_pattern (), mp_view->line_styles (), w, h);
// create frame
if (lw == 0) {
single_bitmap_to_image (lay::ViewOp (frame_color, mode, 0 /*solid line*/, 2 /*dotted*/, 0), frame, &image, mp_view->dither_pattern (), mp_view->line_styles (), w, h);
} else {
single_bitmap_to_image (lay::ViewOp (frame_color, mode, iter->eff_line_style (true), 0, 0, lay::ViewOp::Rect, lw), frame, &image, mp_view->dither_pattern (), mp_view->line_styles (), w, h);
}
// create text
single_bitmap_to_image (lay::ViewOp (frame_color, mode, 0, 0, 0), text, &image, mp_view->dither_pattern (), mp_view->line_styles (), w, h);
// create vertex
single_bitmap_to_image (lay::ViewOp (frame_color, mode, 0, 0, 0, lay::ViewOp::Cross, iter->marked (true) ? 9/*mark size*/ : 0), vertex, &image, mp_view->dither_pattern (),mp_view->line_styles (), w, h);
QPixmap pixmap = QPixmap::fromImage (image); // Qt 4.6.0 workaround
return QVariant (QIcon (pixmap));
return QVariant (icon_for_layer (iter, mp_view, is.width (), is.height (), di_off));
} else {
return QVariant (QIcon ());
}

View File

@ -104,6 +104,16 @@ public:
virtual QModelIndex index (int row, int column, const QModelIndex &parent) const;
virtual QModelIndex parent (const QModelIndex &index) const;
/**
* @brief Provides an icon for a given layer style
*/
static QIcon icon_for_layer (const lay::LayerPropertiesConstIterator &iter, lay::LayoutView *view, unsigned int w, unsigned int h, unsigned int di_offset, bool no_state = false);
/**
* @brief Gets the preferred icon size
*/
QSize icon_size () const;
/**
* @brief Convert a lay::LayerPropertiesConstIterator to a QModelIndex
*/

View File

@ -74,10 +74,7 @@ void
SelectionService::deactivated ()
{
mp_view->clear_transient_selection ();
if (mp_box) {
delete mp_box;
mp_box = 0;
}
reset_box ();
}
void
@ -102,7 +99,20 @@ SelectionService::timeout ()
mp_view->transient_select (m_hover_point);
}
bool
void
SelectionService::reset_box ()
{
if (mp_box) {
widget ()->ungrab_mouse (this);
delete mp_box;
mp_box = 0;
}
}
bool
SelectionService::wheel_event (int /*delta*/, bool /*horizonal*/, const db::DPoint & /*p*/, unsigned int /*buttons*/, bool /*prio*/)
{
return false;
@ -115,19 +125,31 @@ SelectionService::enter_event (bool /*prio*/)
return false;
}
bool
SelectionService::leave_event (bool /*prio*/)
bool
SelectionService::leave_event (bool prio)
{
m_mouse_in_window = false;
hover_reset ();
if (prio) {
reset_box ();
}
return false;
}
bool
SelectionService::mouse_move_event (const db::DPoint &p, unsigned int /*buttons*/, bool prio)
SelectionService::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
{
if (prio) {
m_current_position = p;
if ((buttons & LeftButton) == 0) {
reset_box ();
}
if (mp_box) {
m_p2 = p;
mp_box->set_points (m_p1, m_p2);
@ -138,6 +160,7 @@ SelectionService::mouse_move_event (const db::DPoint &p, unsigned int /*buttons*
}
}
return false;
}
@ -145,6 +168,11 @@ bool
SelectionService::mouse_double_click_event (const db::DPoint & /*p*/, unsigned int buttons, bool prio)
{
hover_reset ();
if (prio) {
reset_box ();
}
if (prio && (buttons & lay::LeftButton) != 0) {
mp_view->show_properties (QApplication::activeWindow ());
return true;
@ -157,11 +185,18 @@ bool
SelectionService::mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio)
{
hover_reset ();
if (prio && ! mp_box && (buttons & lay::LeftButton) != 0) {
mp_view->stop_redraw (); // TODO: how to restart if selection is aborted?
m_buttons = buttons;
begin (p);
return true;
if (prio) {
reset_box ();
if ((buttons & lay::LeftButton) != 0) {
mp_view->stop_redraw (); // TODO: how to restart if selection is aborted?
m_buttons = buttons;
begin (p);
return true;
}
}
return false;
@ -170,7 +205,11 @@ SelectionService::mouse_press_event (const db::DPoint &p, unsigned int buttons,
bool
SelectionService::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio)
{
if (prio && mp_view && widget ()->mouse_event_viewport ().contains (p) && (buttons & lay::LeftButton) != 0) {
if (prio) {
reset_box ();
}
if (prio && mp_view && widget ()->mouse_event_viewport ().contains (p) && (buttons & lay::LeftButton) != 0) {
lay::Editable::SelectionMode mode = lay::Editable::Replace;
bool shift = ((buttons & lay::ShiftButton) != 0);
@ -211,12 +250,10 @@ bool
SelectionService::mouse_release_event (const db::DPoint & /*p*/, unsigned int /*buttons*/, bool prio)
{
hover_reset ();
if (prio && mp_box) {
widget ()->ungrab_mouse (this);
delete mp_box;
mp_box = 0;
reset_box ();
if (mp_view) {

View File

@ -25,6 +25,8 @@
#ifndef HDR_laySelector
#define HDR_laySelector
#include "laybasicCommon.h"
#include "layViewObject.h"
#include "layEditable.h"
@ -37,7 +39,7 @@ class RubberBox;
class LayoutView;
class LayoutCanvas;
class SelectionService
class LAYBASIC_PUBLIC SelectionService
: public QObject,
public lay::ViewService
{
@ -77,6 +79,7 @@ private:
virtual void deactivated ();
db::DPoint m_p1, m_p2;
db::DPoint m_current_position;
lay::LayoutView *mp_view;
lay::RubberBox *mp_box;
unsigned int m_color;
@ -86,6 +89,8 @@ private:
bool m_hover_wait;
db::DPoint m_hover_point;
bool m_mouse_in_window;
void reset_box ();
};
}

View File

@ -272,6 +272,7 @@ ViewObjectWidget::ViewObjectWidget (QWidget *parent, const char *name)
m_mouse_pressed_state (false),
m_mouse_buttons (0),
m_in_mouse_move (false),
m_mouse_inside (false),
m_cursor (lay::Cursor::none),
m_default_cursor (lay::Cursor::none)
{
@ -363,6 +364,14 @@ ViewObjectWidget::set_default_cursor (lay::Cursor::cursor_shape cursor)
}
}
void
ViewObjectWidget::ensure_entered ()
{
if (! m_mouse_inside) {
enterEvent (0);
}
}
void
ViewObjectWidget::begin_mouse_event (lay::Cursor::cursor_shape cursor)
{
@ -434,7 +443,7 @@ BEGIN_PROTECTED
const DragDropDataBase *dd = get_drag_drop_data (event->mimeData ());
if (dd) {
db::DPoint p = m_trans.inverted () * db::DPoint (event->pos ().x (), height () - 1 - event->pos ().y ());
db::DPoint p = pixel_to_um (event->pos ());
bool done = drag_enter_event (p, dd);
service_iterator svc = begin_services ();
@ -479,7 +488,7 @@ BEGIN_PROTECTED
const DragDropDataBase *dd = get_drag_drop_data (event->mimeData ());
if (dd) {
db::DPoint p = m_trans.inverted () * db::DPoint (event->pos ().x (), height () - 1 - event->pos ().y ());
db::DPoint p = pixel_to_um (event->pos ());
bool done = drag_move_event (p, dd);
service_iterator svc = begin_services ();
@ -503,7 +512,7 @@ BEGIN_PROTECTED
const DragDropDataBase *dd = get_drag_drop_data (event->mimeData ());
if (dd) {
db::DPoint p = m_trans.inverted () * db::DPoint (event->pos ().x (), height () - 1 - event->pos ().y ());
db::DPoint p = pixel_to_um (event->pos ());
bool done = drop_event (p, dd);
service_iterator svc = begin_services ();
@ -523,6 +532,7 @@ void
ViewObjectWidget::mouseMoveEvent (QMouseEvent *e)
{
BEGIN_PROTECTED
ensure_entered ();
m_mouse_pos = e->pos ();
m_mouse_buttons = qt_to_buttons (e->buttons (), e->modifiers ());
do_mouse_move ();
@ -543,7 +553,7 @@ ViewObjectWidget::do_mouse_move ()
bool done = false;
db::DPoint p = m_trans.inverted () * db::DPoint (m_mouse_pressed.x (), height () - 1 - m_mouse_pressed.y ());
db::DPoint p = pixel_to_um (m_mouse_pressed);
for (std::list<ViewService *>::iterator g = m_grabbed.begin (); !done && g != m_grabbed.end (); ) {
std::list<ViewService *>::iterator gg = g;
@ -578,7 +588,7 @@ ViewObjectWidget::do_mouse_move ()
bool done = false;
db::DPoint p = m_trans.inverted () * db::DPoint (m_mouse_pos.x (), height () - 1 - m_mouse_pos.y ());
db::DPoint p = pixel_to_um (m_mouse_pos);
for (std::list<ViewService *>::iterator g = m_grabbed.begin (); !done && g != m_grabbed.end (); ) {
std::list<ViewService *>::iterator gg = g;
@ -614,6 +624,7 @@ void
ViewObjectWidget::mouseDoubleClickEvent (QMouseEvent *e)
{
BEGIN_PROTECTED
ensure_entered ();
begin_mouse_event (lay::Cursor::none);
setFocus ();
@ -626,7 +637,7 @@ BEGIN_PROTECTED
unsigned int buttons = qt_to_buttons (e->buttons (), e->modifiers ());
db::DPoint p = m_trans.inverted () * db::DPoint (e->pos ().x (), height () - 1 - e->pos ().y ());
db::DPoint p = pixel_to_um (e->pos ());
for (std::list<ViewService *>::iterator g = m_grabbed.begin (); !done && g != m_grabbed.end (); ) {
std::list<ViewService *>::iterator gg = g;
@ -659,6 +670,8 @@ void
ViewObjectWidget::enterEvent (QEvent * /*event*/)
{
BEGIN_PROTECTED
m_mouse_inside = true;
begin_mouse_event ();
bool done = false;
@ -723,12 +736,15 @@ BEGIN_PROTECTED
end_mouse_event ();
END_PROTECTED
m_mouse_inside = false;
}
void
ViewObjectWidget::wheelEvent (QWheelEvent *e)
{
BEGIN_PROTECTED
ensure_entered ();
begin_mouse_event ();
e->ignore ();
@ -738,7 +754,7 @@ BEGIN_PROTECTED
unsigned int buttons = qt_to_buttons (e->buttons (), e->modifiers ());
bool horizonal = (e->orientation () == Qt::Horizontal);
db::DPoint p = m_trans.inverted () * db::DPoint (e->pos ().x (), height () - 1 - e->pos ().y ());
db::DPoint p = pixel_to_um (e->pos ());
for (std::list<ViewService *>::iterator g = m_grabbed.begin (); !done && g != m_grabbed.end (); ) {
std::list<ViewService *>::iterator gg = g;
@ -770,6 +786,7 @@ END_PROTECTED
void
ViewObjectWidget::mousePressEvent (QMouseEvent *e)
{
ensure_entered ();
setFocus ();
m_mouse_pos = e->pos ();
@ -784,12 +801,13 @@ void
ViewObjectWidget::mouseReleaseEvent (QMouseEvent *e)
{
BEGIN_PROTECTED
ensure_entered ();
begin_mouse_event ();
bool done = false;
m_mouse_pos = e->pos ();
db::DPoint p = m_trans.inverted () * db::DPoint (e->pos ().x (), height () - 1 - e->pos ().y ());
db::DPoint p = pixel_to_um (e->pos ());
for (std::list<ViewService *>::iterator g = m_grabbed.begin (); !done && g != m_grabbed.end (); ) {
std::list<ViewService *>::iterator gg = g;
@ -838,6 +856,12 @@ END_PROTECTED
m_mouse_pressed_state = false;
}
db::DPoint
ViewObjectWidget::pixel_to_um (const QPoint &pt) const
{
return m_trans.inverted () * db::DPoint (pt.x (), height () - 1 - pt.y ());
}
void
ViewObjectWidget::mouse_event_trans (const db::DCplxTrans &trans)
{

View File

@ -962,6 +962,35 @@ public:
return m_view_objects_dismissed;
}
/**
* @brief Gets the current mouse position
*/
QPoint mouse_position () const
{
return m_mouse_pos;
}
/**
* @brief Gets the current mouse position in micrometer units
*/
db::DPoint mouse_position_um () const
{
return pixel_to_um (m_mouse_pos);
}
/**
* @brief Translates a screen coordinate in micrometer coordinates
*/
db::DPoint pixel_to_um (const QPoint &pt) const;
/**
* @brief Gets a flag indicating whether the mouse is inside the window
*/
bool mouse_in_window () const
{
return m_mouse_inside;
}
protected:
/**
* @brief Qt focus event handler
@ -1052,8 +1081,10 @@ private:
bool m_mouse_pressed_state;
unsigned int m_mouse_buttons;
bool m_in_mouse_move;
bool m_mouse_inside;
lay::Cursor::cursor_shape m_cursor, m_default_cursor;
void ensure_entered ();
void do_mouse_move ();
void begin_mouse_event (lay::Cursor::cursor_shape cursor = lay::Cursor::keep);
void end_mouse_event ();