diff --git a/src/edt/edt/edtMainService.cc b/src/edt/edt/edtMainService.cc index a5068438c..1fd2d3340 100644 --- a/src/edt/edt/edtMainService.cc +++ b/src/edt/edt/edtMainService.cc @@ -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 +#include +#include 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_services = view ()->get_plugins (); + 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::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 > 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 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 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::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 diff --git a/src/laybasic/laybasic/layBitmap.cc b/src/laybasic/laybasic/layBitmap.cc index 1c9c76336..ad857de2e 100644 --- a/src/laybasic/laybasic/layBitmap.cc +++ b/src/laybasic/laybasic/layBitmap.cc @@ -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 { diff --git a/src/laybasic/laybasic/layBitmap.h b/src/laybasic/laybasic/layBitmap.h index e225134e5..07dc3bb2a 100644 --- a/src/laybasic/laybasic/layBitmap.h +++ b/src/laybasic/laybasic/layBitmap.h @@ -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 * diff --git a/src/laybasic/laybasic/layFinder.cc b/src/laybasic/laybasic/layFinder.cc index 835b5c1ac..cd5d8215b 100644 --- a/src/laybasic/laybasic/layFinder.cc +++ b/src/laybasic/laybasic/layFinder.cc @@ -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::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; } diff --git a/src/laybasic/laybasic/layFinder.h b/src/laybasic/laybasic/layFinder.h index c183f5346..98684c80c 100644 --- a/src/laybasic/laybasic/layFinder.h +++ b/src/laybasic/laybasic/layFinder.h @@ -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 &path () const { return m_path; @@ -166,6 +190,7 @@ private: std::vector m_layers; double m_distance; bool m_point_mode; + bool m_catch_all; bool m_top_level_sel; db::box_convert m_box_convert; db::box_convert m_cell_box_convert; diff --git a/src/laybasic/laybasic/layLayerControlPanel.cc b/src/laybasic/laybasic/layLayerControlPanel.cc index be8eda762..28ab6a8bc 100644 --- a/src/laybasic/laybasic/layLayerControlPanel.cc +++ b/src/laybasic/laybasic/layLayerControlPanel.cc @@ -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); diff --git a/src/laybasic/laybasic/layLayerTreeModel.cc b/src/laybasic/laybasic/layLayerTreeModel.cc index 3a6ce2f77..c622bf5e4 100644 --- a/src/laybasic/laybasic/layLayerTreeModel.cc +++ b/src/laybasic/laybasic/layLayerTreeModel.cc @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -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 ()); } diff --git a/src/laybasic/laybasic/layLayerTreeModel.h b/src/laybasic/laybasic/layLayerTreeModel.h index b52d7cdaf..852184ab1 100644 --- a/src/laybasic/laybasic/layLayerTreeModel.h +++ b/src/laybasic/laybasic/layLayerTreeModel.h @@ -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 */ diff --git a/src/laybasic/laybasic/laySelector.cc b/src/laybasic/laybasic/laySelector.cc index ffe76e411..d1e5d1425 100644 --- a/src/laybasic/laybasic/laySelector.cc +++ b/src/laybasic/laybasic/laySelector.cc @@ -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) { diff --git a/src/laybasic/laybasic/laySelector.h b/src/laybasic/laybasic/laySelector.h index ddf60c6f8..e302d70f4 100644 --- a/src/laybasic/laybasic/laySelector.h +++ b/src/laybasic/laybasic/laySelector.h @@ -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 (); }; } diff --git a/src/laybasic/laybasic/layViewObject.cc b/src/laybasic/laybasic/layViewObject.cc index cc68a61f8..ef2a7dbfb 100644 --- a/src/laybasic/laybasic/layViewObject.cc +++ b/src/laybasic/laybasic/layViewObject.cc @@ -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::iterator g = m_grabbed.begin (); !done && g != m_grabbed.end (); ) { std::list::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::iterator g = m_grabbed.begin (); !done && g != m_grabbed.end (); ) { std::list::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::iterator g = m_grabbed.begin (); !done && g != m_grabbed.end (); ) { std::list::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::iterator g = m_grabbed.begin (); !done && g != m_grabbed.end (); ) { std::list::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::iterator g = m_grabbed.begin (); !done && g != m_grabbed.end (); ) { std::list::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) { diff --git a/src/laybasic/laybasic/layViewObject.h b/src/laybasic/laybasic/layViewObject.h index 816241d2b..4522857cf 100644 --- a/src/laybasic/laybasic/layViewObject.h +++ b/src/laybasic/laybasic/layViewObject.h @@ -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 ();