/* * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 Claire Xenia Wolf * Copyright (C) 2019 Miodrag Milanovic * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ #include "gfx.h" NEXTPNR_NAMESPACE_BEGIN const float slice_x1 = 0.92; const float slice_x2 = 0.94; const float slice_x2_wide = 0.97; const float slice_y1 = 0.71; const float slice_y2 = 0.745 + 0.0068; const float slice_pitch = 0.0374 + 0.0068; const float slice_comb_dx1 = 0.002; const float slice_comb_w = 0.007; const float slice_ff_dx1 = 0.011; const float slice_ff_w = 0.007; const float slice_comb_dy1 = 0.002; const float slice_comb_h = 0.014; const float slice_comb_dy2 = 0.021; const float io_cell_v_x1 = 0.76; const float io_cell_v_x2 = 0.95; const float io_cell_v_y1 = 0.05; const float io_cell_gap = 0.10; const float io_cell_h_x1 = 0.05; const float io_cell_h_y1 = 0.05; const float io_cell_h_y2 = 0.24; const float wire_distance = 0.0017f; const float wire_distance_small = 0.00085f; const float wire_length_lut = 0.01f; const float wire_length = 0.005f; const float wire_length_long = 0.015f; const float dll_cell_x1 = 0.2; const float dll_cell_x2 = 0.8; const float dll_cell_y1 = 0.2; const float dll_cell_y2 = 0.8; void gfxTileBel(std::vector &g, int x, int y, int z, int w, int h, IdString bel_type, GraphicElement::style_t style) { GraphicElement el; el.type = GraphicElement::TYPE_BOX; el.style = style; if (bel_type == id_TRELLIS_COMB) { int lc = (z >> Arch::lc_idx_shift); el.x1 = x + slice_x1 + slice_comb_dx1; el.x2 = el.x1 + slice_comb_w; el.y1 = y + slice_y1 + (lc / 2) * slice_pitch + ((lc % 2) ? slice_comb_dy2 : slice_comb_dy1); el.y2 = el.y1 + slice_comb_h; g.push_back(el); el.style = GraphicElement::STYLE_FRAME; if ((lc % 2) == 0) { // SLICE frame el.x1 = x + slice_x1; el.x2 = x + slice_x2; el.y1 = y + slice_y1 + (lc / 2) * slice_pitch; el.y2 = y + slice_y2 + (lc / 2) * slice_pitch; g.push_back(el); // SLICE control set switchbox el.x1 = x + slice_x2 + 15 * wire_distance; el.x2 = el.x1 + wire_distance; el.y1 = y + slice_y2 - wire_distance * (TILE_WIRE_CLK3_SLICE - TILE_WIRE_DUMMY_D2 + 5 + (3 - (lc / 2)) * 26) + 3 * slice_pitch - 0.0007f; el.y2 = el.y1 + wire_distance * 5; g.push_back(el); } // LUT permutation switchbox el.x1 = x + slice_x1 - wire_length_lut; el.x2 = x + slice_x1 - wire_length; int start_wire = (TILE_WIRE_D7 + 24 * (lc / 2) + 4 * (lc % 2)); el.y2 = y + slice_y2 - wire_distance * (start_wire - TILE_WIRE_FCO + 1 + (lc / 2) * 2) + 3 * slice_pitch + 0.25 * wire_distance; el.y1 = el.y2 - 3.5 * wire_distance; g.push_back(el); } else if (bel_type == id_TRELLIS_FF) { int lc = (z >> Arch::lc_idx_shift); el.x1 = x + slice_x1 + slice_ff_dx1; el.x2 = el.x1 + slice_ff_w; el.y1 = y + slice_y1 + (lc / 2) * slice_pitch + ((lc % 2) ? slice_comb_dy2 : slice_comb_dy1); el.y2 = el.y1 + slice_comb_h; g.push_back(el); } else if (bel_type.in(id_TRELLIS_IO, id_IOLOGIC, id_SIOLOGIC, id_DQSBUFM)) { bool top_bottom = (y == 0 || y == (h - 1)); if (top_bottom) { el.x1 = x + io_cell_h_x1 + (z + 2) * io_cell_gap; el.x2 = x + io_cell_h_x1 + (z + 2) * io_cell_gap + 0.08f; if (y == h - 1) { el.y1 = y + 1 - io_cell_h_y1; el.y2 = y + 1 - io_cell_h_y2; } else { el.y1 = y + io_cell_h_y1; el.y2 = y + io_cell_h_y2; } } else { if (x == 0) { el.x1 = x + 1 - io_cell_v_x1; el.x2 = x + 1 - io_cell_v_x2; } else { el.x1 = x + io_cell_v_x1; el.x2 = x + io_cell_v_x2; } el.y1 = y + io_cell_v_y1 + z * io_cell_gap; el.y2 = y + io_cell_v_y1 + z * io_cell_gap + 0.08f; } g.push_back(el); } else if (bel_type == id_DCCA) { el.x1 = x + switchbox_x1 + (z)*0.025; el.y1 = y + 0.14; el.x2 = x + switchbox_x1 + (z)*0.025 + 0.020; el.y2 = y + 0.18; g.push_back(el); } else if (bel_type.in(id_DP16KD, id_MULT18X18D, id_ALU54B)) { el.x1 = x + slice_x1; el.x2 = x + slice_x2_wide; el.y1 = y + slice_y1 - 1 * slice_pitch; el.y2 = y + slice_y2 + 3 * slice_pitch; g.push_back(el); } else if (bel_type == id_EHXPLLL) { el.x1 = x + slice_x1; el.x2 = x + slice_x2_wide; el.y1 = y + slice_y1; el.y2 = y + slice_y2; g.push_back(el); } else if (bel_type == id_DCUA) { el.x1 = x + slice_x1; el.x2 = x + slice_x2_wide; el.y1 = y + slice_y2; el.y2 = y + 0.25; g.push_back(el); } else if (bel_type.in(id_EXTREFB, id_PCSCLKDIV, id_DTR, id_USRMCLK, id_SEDGA, id_GSR, id_JTAGG, id_OSCG)) { el.x1 = x + slice_x1; el.x2 = x + slice_x2_wide; el.y1 = y + slice_y1 + (z)*slice_pitch; el.y2 = y + slice_y2 + (z)*slice_pitch; g.push_back(el); } else if (bel_type == id_DDRDLL) { el.x1 = x + dll_cell_x1; el.x2 = x + dll_cell_x2; el.y1 = y + dll_cell_y1; el.y2 = y + dll_cell_y2; g.push_back(el); } else if (bel_type.in(id_DLLDELD, id_CLKDIVF, id_ECLKSYNCB, id_TRELLIS_ECLKBUF, id_ECLKBRIDGECS)) { el.x1 = x + 0.1 + z * 0.05; el.x2 = x + 0.14 + z * 0.05; el.y1 = y + 0.475; el.y2 = y + 0.525; g.push_back(el); } } void gfxTileWire(std::vector &g, int x, int y, int w, int h, IdString wire_type, GfxTileWireId tilewire, GraphicElement::style_t style) { GraphicElement el; el.type = GraphicElement::TYPE_LINE; el.style = style; if (wire_type == id_WIRE_TYPE_SLICE && tilewire != GfxTileWireId::TILE_WIRE_NONE) { if (tilewire >= TILE_WIRE_FCO_SLICE && tilewire <= TILE_WIRE_FCI_SLICE) { int gap = (tilewire - TILE_WIRE_FCO_SLICE) / 24; int item = (tilewire - TILE_WIRE_FCO_SLICE) % 24; el.x1 = x + slice_x1 - wire_length; el.x2 = x + slice_x1; el.y1 = y + slice_y2 - wire_distance * (tilewire - TILE_WIRE_FCO_SLICE + 1 + gap * 2) + 3 * slice_pitch; el.y2 = el.y1; g.push_back(el); // FX to F connection - top if (item == (TILE_WIRE_FXD_SLICE - TILE_WIRE_FCO_SLICE)) { el.x2 = el.x1; el.y2 = el.y1 - wire_distance; g.push_back(el); } // F5 to F connection - bottom if (item == (TILE_WIRE_F5D_SLICE - TILE_WIRE_FCO_SLICE)) { el.x2 = el.x1; el.y2 = el.y1 + wire_distance; g.push_back(el); } // connection between slices if (item == (TILE_WIRE_FCID_SLICE - TILE_WIRE_FCO_SLICE) && tilewire != TILE_WIRE_FCI_SLICE) { el.x2 = el.x1; el.y2 = el.y1 - wire_distance * 3; g.push_back(el); } } if (tilewire >= TILE_WIRE_DUMMY_D2 && tilewire <= TILE_WIRE_WAD0A_SLICE) { int gap = (tilewire - TILE_WIRE_DUMMY_D2) / 12; el.x1 = x + slice_x2 + wire_length; el.x2 = x + slice_x2; el.y1 = y + slice_y2 - wire_distance * (tilewire - TILE_WIRE_DUMMY_D2 + 1 + gap * 14) + 3 * slice_pitch; el.y2 = el.y1; g.push_back(el); } } else if (wire_type == id_WIRE_TYPE_H02) { if (x == 0) el.x1 = 0.9; else el.x1 = x + switchbox_x1 + wire_distance * (20 + (tilewire - TILE_WIRE_H02W0701) + 20 * (x % 3)); el.x2 = el.x1; el.y1 = y + switchbox_y1; el.y2 = y + switchbox_y1 - wire_distance * (20 + (tilewire - TILE_WIRE_H02W0701) + 20 * (x % 3)); if (x != 0 && x != w - 1) g.push_back(el); if (x == w - 2) el.x2 = x + 1 + 0.1; else el.x2 = x + 1 + switchbox_x1 + wire_distance * (20 + (tilewire - TILE_WIRE_H02W0701) + 20 * (x % 3)); el.y1 = el.y2; if (x != w - 1) g.push_back(el); el.x1 = el.x2; el.y1 = y + switchbox_y1; if (x != w - 1 && x != w - 2) g.push_back(el); if (x == w - 1) el.x1 = x + 0.1; else el.x1 = x + switchbox_x1 + wire_distance * (20 + (tilewire - TILE_WIRE_H02W0701) + 20 * (x % 3)); if (x == 1) el.x2 = x - 1 + 0.9; else el.x2 = x - 1 + switchbox_x1 + wire_distance * (20 + (tilewire - TILE_WIRE_H02W0701) + 20 * (x % 3)); el.y2 = y + switchbox_y1 - wire_distance * (20 + (tilewire - TILE_WIRE_H02W0701) + 20 * (x % 3)); el.y1 = el.y2; if (x != 0) g.push_back(el); el.x1 = el.x2; el.y1 = y + switchbox_y1; if (x != 0 && x != 1) g.push_back(el); } else if (wire_type == id_WIRE_TYPE_V02) { if (y == 0) el.y1 = 0.9; else el.y1 = y + switchbox_y1 + wire_distance * (20 + (tilewire - TILE_WIRE_V02N0701) + 20 * (y % 3)); el.y2 = el.y1; el.x1 = x + switchbox_x1; el.x2 = x + switchbox_x1 - wire_distance * (20 + (tilewire - TILE_WIRE_V02N0701) + 20 * (y % 3)); if (y != 0 && y != h - 1) g.push_back(el); if (y == h - 2) el.y2 = y + 1 + 0.1; else el.y2 = y + 1 + switchbox_y1 + wire_distance * (20 + (tilewire - TILE_WIRE_V02N0701) + 20 * (y % 3)); el.x1 = el.x2; if (y != h - 1) g.push_back(el); el.y1 = el.y2; el.x1 = x + switchbox_x1; if (y != h - 1 && y != h - 2) g.push_back(el); if (y == h - 1) el.y1 = y + 0.1; else el.y1 = y + switchbox_y1 + wire_distance * (20 + (tilewire - TILE_WIRE_V02N0701) + 20 * (y % 3)); if (y == 1) el.y2 = y - 1 + 0.9; else el.y2 = y - 1 + switchbox_y1 + wire_distance * (20 + (tilewire - TILE_WIRE_V02N0701) + 20 * (y % 3)); el.x2 = x + switchbox_x1 - wire_distance * (20 + (tilewire - TILE_WIRE_V02N0701) + 20 * (y % 3)); el.x1 = el.x2; if (y != 0) g.push_back(el); el.y1 = el.y2; el.x1 = x + switchbox_x1; if (y != 0 && y != 1) g.push_back(el); } else if (wire_type == id_WIRE_TYPE_H06) { if (x == 0) el.x1 = 0.9; else el.x1 = x + switchbox_x1 + wire_distance * (96 + (tilewire - TILE_WIRE_H06W0303) + 10 * (x % 9)); el.x2 = el.x1; el.y1 = y + switchbox_y1; el.y2 = y + switchbox_y1 - wire_distance * (96 + (tilewire - TILE_WIRE_H06W0303) + 10 * (x % 9)); if (x != 0 && x != w - 1) g.push_back(el); if (x == w - 2 || x == w - 3 || x == w - 4) el.x2 = w - 1 + 0.1; else el.x2 = x + 3 + switchbox_x1 + wire_distance * (96 + (tilewire - TILE_WIRE_H06W0303) + 10 * (x % 9)); el.y1 = el.y2; if (x != w - 1) g.push_back(el); el.x1 = el.x2; el.y1 = y + switchbox_y1; if (x != w - 1 && x != w - 2 && x != w - 3 && x != w - 4) g.push_back(el); if (x == w - 1) el.x1 = x + 0.1; else el.x1 = x + switchbox_x1 + wire_distance * (96 + (tilewire - TILE_WIRE_H06W0303) + 10 * (x % 9)); if (x == 1 || x == 2 || x == 3) el.x2 = 0.9; else el.x2 = x - 3 + switchbox_x1 + wire_distance * (96 + (tilewire - TILE_WIRE_H06W0303) + 10 * (x % 9)); el.y2 = y + switchbox_y1 - wire_distance * (96 + (tilewire - TILE_WIRE_H06W0303) + 10 * (x % 9)); el.y1 = el.y2; if (x != 0) g.push_back(el); el.x1 = el.x2; el.y1 = y + switchbox_y1; if (x != 0 && x != 1 && x != 2 && x != 3) g.push_back(el); } else if (wire_type == id_WIRE_TYPE_V06) { if (y == 0) el.y1 = 0.9; else el.y1 = y + switchbox_y1 + wire_distance * (96 + (tilewire - TILE_WIRE_V06N0303) + 10 * (y % 9)); el.y2 = el.y1; el.x1 = x + switchbox_x1; el.x2 = x + switchbox_x1 - wire_distance * (96 + (tilewire - TILE_WIRE_V06N0303) + 10 * (y % 9)); if (y != 0 && y != h - 1) g.push_back(el); if (y == h - 2 || y == h - 3 || y == h - 4) el.y2 = h - 1 + 0.1; else el.y2 = y + 3 + switchbox_y1 + wire_distance * (96 + (tilewire - TILE_WIRE_V06N0303) + 10 * (y % 9)); el.x1 = el.x2; if (y != h - 1) g.push_back(el); el.y1 = el.y2; el.x1 = x + switchbox_x1; if (y != h - 1 && y != h - 2 && y != h - 3 && y != h - 4) g.push_back(el); if (y == h - 1) el.y1 = y + 0.1; else el.y1 = y + switchbox_y1 + wire_distance * (96 + (tilewire - TILE_WIRE_V06N0303) + 10 * (y % 9)); if (y == 1 || y == 2 || y == 3) el.y2 = 0.9; else el.y2 = y - 3 + switchbox_y1 + wire_distance * (96 + (tilewire - TILE_WIRE_V06N0303) + 10 * (y % 9)); el.x2 = x + switchbox_x1 - wire_distance * (96 + (tilewire - TILE_WIRE_V06N0303) + 10 * (y % 9)); el.x1 = el.x2; if (y != 0) g.push_back(el); el.y1 = el.y2; el.x1 = x + switchbox_x1; if (y != 0 && y != 1 && y != 2 && y != 3) g.push_back(el); } else if (wire_type == id_WIRE_TYPE_V01) { if (tilewire >= TILE_WIRE_V01N0001 && tilewire <= TILE_WIRE_V01S0100) { el.x1 = x + switchbox_x1 + wire_distance * (10 + tilewire - TILE_WIRE_V01N0001); el.x2 = el.x1; if (y == h - 2) el.y1 = y + 1.1; else el.y1 = y + switchbox_y1 + 1; if (y == 0) el.y2 = y + 0.9; else el.y2 = y + switchbox_y2; g.push_back(el); } } else if (wire_type == id_WIRE_TYPE_H01) { if (tilewire >= TILE_WIRE_H01E0001 && tilewire <= TILE_WIRE_HL7W0001) { if (x == w - 1) el.x1 = x + 0.1; else el.x1 = x + switchbox_x1; if (x == 1) el.x2 = x - 0.1; else el.x2 = x + switchbox_x2 - 1; el.y1 = y + switchbox_y1 + wire_distance * (10 + tilewire - TILE_WIRE_H01E0001); el.y2 = el.y1; g.push_back(el); } } else if (wire_type == id_WIRE_TYPE_V00) { int group = (tilewire - TILE_WIRE_V00T0000) / 2; el.x1 = x + switchbox_x2 - wire_distance * (8 - ((tilewire - TILE_WIRE_V00T0000) % 2) * 4); el.x2 = el.x1; if (group) { el.y1 = y + switchbox_y1; el.y2 = y + switchbox_y1 - wire_distance * 4; } else { el.y1 = y + switchbox_y2; el.y2 = y + switchbox_y2 + wire_distance * 4; } g.push_back(el); } else if (wire_type == id_WIRE_TYPE_H00) { int group = (tilewire - TILE_WIRE_H00L0000) / 2; el.y1 = y + switchbox_y1 + wire_distance * (8 - ((tilewire - TILE_WIRE_H00L0000) % 2) * 4); el.y2 = el.y1; if (group) { el.x1 = x + switchbox_x2 + wire_distance * 4; el.x2 = x + switchbox_x2; } else { el.x1 = x + switchbox_x1 - wire_distance * 4; el.x2 = x + switchbox_x1; } g.push_back(el); } else if (wire_type == id_WIRE_TYPE_NONE) { if (tilewire >= TILE_WIRE_NBOUNCE && tilewire <= TILE_WIRE_SBOUNCE) { el.x1 = x + switchbox_x2 - wire_distance * 4; el.x2 = x + switchbox_x2 - wire_distance * 8; if (tilewire == TILE_WIRE_NBOUNCE) { el.y1 = y + switchbox_y2 + wire_distance * 4; el.y2 = el.y1; } else { el.y1 = y + switchbox_y1 - wire_distance * 4; el.y2 = el.y1; } g.push_back(el); } else if (tilewire >= TILE_WIRE_WBOUNCE && tilewire <= TILE_WIRE_EBOUNCE) { el.y1 = y + switchbox_y1 + wire_distance * 4; el.y2 = y + switchbox_y1 + wire_distance * 8; if (tilewire == TILE_WIRE_WBOUNCE) { el.x1 = x + switchbox_x1 - wire_distance * 4; el.x2 = el.x1; } else { el.x1 = x + switchbox_x2 + wire_distance * 4; el.x2 = el.x1; } g.push_back(el); } else if (tilewire >= TILE_WIRE_CLK0 && tilewire <= TILE_WIRE_LSR1) { el.x1 = x + switchbox_x2; el.x2 = x + slice_x2 + 15 * wire_distance + (8 - (tilewire - TILE_WIRE_CLK0)) * wire_distance; el.y1 = y + slice_y2 - wire_distance * (tilewire - TILE_WIRE_CLK0 - 5) + 3 * slice_pitch; el.y2 = el.y1; g.push_back(el); el.x1 = el.x2; el.y2 = y + slice_y2 - wire_distance * (3 + (tilewire - TILE_WIRE_CLK0)); g.push_back(el); for (int i = 0; i < 4; i++) { el.x1 = x + slice_x2 + 15 * wire_distance + wire_distance; el.x2 = x + slice_x2 + 15 * wire_distance + (8 - (tilewire - TILE_WIRE_CLK0)) * wire_distance; el.y1 = y + slice_y2 - wire_distance * (TILE_WIRE_CLK3_SLICE - TILE_WIRE_DUMMY_D2 + 1 + tilewire - TILE_WIRE_CLK0) + i * slice_pitch; el.y2 = el.y1; g.push_back(el); } if (tilewire == TILE_WIRE_CLK1 || tilewire == TILE_WIRE_LSR1) { for (int i = 0; i < 2; i++) { el.x1 = x + slice_x2 + 3 * wire_distance; el.x2 = x + slice_x2 + 15 * wire_distance + (8 - (tilewire - TILE_WIRE_CLK0)) * wire_distance; el.y1 = y + slice_y2 - wire_distance * (TILE_WIRE_CLK3_SLICE - TILE_WIRE_DUMMY_D2 - 1 + (tilewire - TILE_WIRE_CLK0) / 2) + i * slice_pitch; el.y2 = el.y1; g.push_back(el); } } } // TRELLIS_IO wires else if (tilewire >= TILE_WIRE_JDIA && tilewire <= TILE_WIRE_ECLKD) { el.x1 = x + 0.5f; el.x2 = x + 0.5f + wire_length; bool top = (y == (h - 1)); if (top) el.y1 = y + 1 - (slice_y2 - wire_distance * (tilewire - TILE_WIRE_JDIA + 1) + 3 * slice_pitch); else el.y1 = y + slice_y2 - wire_distance * (tilewire - TILE_WIRE_JDIA + 1) + 3 * slice_pitch; el.y2 = el.y1; g.push_back(el); } else if (tilewire >= TILE_WIRE_JCE0 && tilewire <= TILE_WIRE_JQ7) { el.x1 = x + switchbox_x2; el.x2 = x + switchbox_x2 + wire_length; el.y1 = y + slice_y2 - wire_distance * (tilewire - TILE_WIRE_JCE0 + 1) + 3 * slice_pitch; el.y2 = el.y1; g.push_back(el); } else if (tilewire >= TILE_WIRE_FCO && tilewire <= TILE_WIRE_FCI) { int gap = (tilewire - TILE_WIRE_FCO) / 24; int purpose = (tilewire - TILE_WIRE_FCO) % 24; el.x1 = x + switchbox_x2; if (purpose >= (TILE_WIRE_D7 - TILE_WIRE_FCO) && purpose <= (TILE_WIRE_A6 - TILE_WIRE_FCO)) { // Space for the LUT permutation switchbox el.x2 = x + slice_x1 - wire_length_lut; } else { el.x2 = x + slice_x1 - wire_length; } el.y1 = y + slice_y2 - wire_distance * (tilewire - TILE_WIRE_FCO + 1 + gap * 2) + 3 * slice_pitch; el.y2 = el.y1; g.push_back(el); } else if (tilewire >= TILE_WIRE_MUXCLK3 && tilewire <= TILE_WIRE_MUXLSR0) { int gap = (tilewire - TILE_WIRE_MUXCLK3) / 2; int part = (tilewire - TILE_WIRE_MUXCLK3) % 2; el.x1 = x + slice_x2 + 3 * wire_distance; el.x2 = x + slice_x2 + 15 * wire_distance; el.y1 = y + slice_y2 - wire_distance * (TILE_WIRE_CLK3_SLICE - TILE_WIRE_DUMMY_D2 + 1 + part + gap * 26) + 3 * slice_pitch; el.y2 = el.y1; g.push_back(el); } else if (tilewire >= TILE_WIRE_WD3 && tilewire <= TILE_WIRE_WD0) { int part = (tilewire - TILE_WIRE_WD3) % 4; int group = (tilewire - TILE_WIRE_WD3) / 2; el.x1 = x + slice_x2 + wire_length; el.x2 = x + slice_x2 + wire_length + wire_distance * (4 - part); el.y1 = y + slice_y2 - wire_distance * (TILE_WIRE_WDO3C_SLICE - TILE_WIRE_DUMMY_D2 + 1 + part + 14) + 3 * slice_pitch; el.y2 = el.y1; g.push_back(el); el.x1 = el.x2; el.y2 = y + slice_y2 - wire_distance * (TILE_WIRE_WD1B_SLICE - TILE_WIRE_DUMMY_D2 + 1 + (part & 1) + 14 * 2) + (3 - group) * slice_pitch; g.push_back(el); el.x1 = x + slice_x2 + wire_length; el.y1 = el.y2; g.push_back(el); } else if (tilewire >= TILE_WIRE_WAD3 && tilewire <= TILE_WIRE_WAD0) { int part = (tilewire - TILE_WIRE_WAD3) % 4; el.x1 = x + slice_x2 + wire_length; el.x2 = x + slice_x2 + wire_length + wire_distance * (8 - part); el.y1 = y + slice_y2 - wire_distance * (TILE_WIRE_WADO3C_SLICE - TILE_WIRE_DUMMY_D2 + 1 + part + 14) + 3 * slice_pitch; el.y2 = el.y1; g.push_back(el); el.x1 = el.x2; el.y2 = y + slice_y2 - wire_distance * (TILE_WIRE_WAD3B_SLICE - TILE_WIRE_DUMMY_D2 + 1 + part + 14 * 2) + 2 * slice_pitch; g.push_back(el); el.x1 = x + slice_x2 + wire_length; el.y1 = el.y2; g.push_back(el); // middle line el.x1 = x + slice_x2 + wire_length; el.x2 = x + slice_x2 + wire_length + wire_distance * (8 - part); el.y2 = y + slice_y2 - wire_distance * (TILE_WIRE_WAD3B_SLICE - TILE_WIRE_DUMMY_D2 + 1 + part + 14 * 2) + 3 * slice_pitch; el.y1 = el.y2; g.push_back(el); } } else if (wire_type == id_WIRE_TYPE_G_HPBX) { el.x1 = x; el.x2 = x + 1; el.y1 = y + 0.1f + wire_distance * (tilewire - TILE_WIRE_G_HPBX0000 + 1); el.y2 = el.y1; g.push_back(el); el.x1 = x + switchbox_x1 + wire_distance * (200 + (tilewire - TILE_WIRE_G_HPBX0000)); el.x2 = el.x1; el.y2 = y + switchbox_y1; g.push_back(el); } else if (wire_type == id_WIRE_TYPE_G_VPTX) { el.x1 = x + 0.1f + wire_distance * (tilewire - TILE_WIRE_G_VPTX0000 + 1); el.x2 = el.x1; el.y1 = y; el.y2 = y + 1; g.push_back(el); } else if (wire_type == id_WIRE_TYPE_L_HPBX) { el.x1 = x - 3; el.x2 = x + 0.08f; el.y1 = y + wire_distance + wire_distance * (tilewire - TILE_WIRE_L_HPBX0000 + 1); el.y2 = el.y1; g.push_back(el); } else if (wire_type == id_WIRE_TYPE_R_HPBX) { el.x1 = x + 0.2; el.x2 = x + 3; el.y1 = y + wire_distance + wire_distance * (tilewire - TILE_WIRE_R_HPBX0000 + 1); el.y2 = el.y1; g.push_back(el); } else if (wire_type == id_WIRE_TYPE_PIO) { bool top_bottom = (y == 0 || y == (h - 1)); int gap = 3 - (tilewire - TILE_WIRE_PADDOD_PIO) / 7; int num = (tilewire - TILE_WIRE_PADDOD_PIO) % 7; if (top_bottom) { el.x1 = x + io_cell_h_x1 + (gap + 2) * io_cell_gap + wire_distance * (num + 1); el.x2 = el.x1; if (y == h - 1) { el.y1 = y + 1 - io_cell_h_y2; el.y2 = el.y1 - wire_length_long; } else { el.y1 = y + io_cell_h_y2; el.y2 = el.y1 + wire_length_long; } } else { if (x == 0) { el.x1 = x + 1 - io_cell_v_x1; el.x2 = el.x1 + wire_length_long; } else { el.x1 = x + io_cell_v_x1; el.x2 = el.x1 - wire_length_long; } el.y1 = y + io_cell_v_y1 + gap * io_cell_gap + wire_distance * (num + 1); el.y2 = el.y1; } g.push_back(el); } else if (wire_type == id_WIRE_TYPE_DDRDLL) { int num = (tilewire - TILE_WIRE_DDRDEL_DDRDLL); el.x1 = x + io_cell_h_x1 + 0.2 + wire_distance * (num + 1); el.x2 = el.x1; if (y == h - 1) { el.y1 = y + dll_cell_y1; el.y2 = el.y1 - wire_length_long; } else { el.y1 = y + dll_cell_y2; el.y2 = el.y1 + wire_length_long; } g.push_back(el); } else if (wire_type == id_WIRE_TYPE_CCLK) { int num = (tilewire - TILE_WIRE_JPADDI_CCLK); el.x1 = x + slice_x1 + wire_distance * (num + 1); el.x2 = el.x1; el.y1 = y + slice_y2 - 1 * slice_pitch; el.y2 = el.y1 - wire_length_long; g.push_back(el); } else if (wire_type == id_WIRE_TYPE_IOLOGIC) { int gap = 7 - (tilewire - TILE_WIRE_JLOADND_IOLOGIC) / 42; int num = (tilewire - TILE_WIRE_JLOADND_IOLOGIC) % 42; if (x == 0) { el.x1 = x + 1 - io_cell_v_x1; el.x2 = el.x1 + wire_length_long; } else { el.x1 = x + io_cell_v_x1; el.x2 = el.x1 - wire_length_long; } el.y1 = y + io_cell_v_y1 + gap * io_cell_gap + wire_distance * (num + 1); el.y2 = el.y1; g.push_back(el); } else if (wire_type == id_WIRE_TYPE_SIOLOGIC) { int gap = (tilewire - TILE_WIRE_JLOADNB_SIOLOGIC) / 20; int num = (tilewire - TILE_WIRE_JLOADNB_SIOLOGIC) % 20; el.x1 = x + io_cell_h_x1 + (5 - gap) * io_cell_gap + wire_distance * (num + 1); el.x2 = el.x1; if (y == h - 1) { el.y1 = y + 1 - io_cell_h_y2; el.y2 = el.y1 - wire_length_long; } else { el.y1 = y + io_cell_h_y2; el.y2 = el.y1 + wire_length_long; } g.push_back(el); } else if (wire_type == id_WIRE_TYPE_DQS) { int num = (tilewire - TILE_WIRE_DDRDEL_DQS); if (x == 0) { el.x1 = x + 1 - io_cell_v_x1; el.x2 = el.x1 + wire_length_long; } else { el.x1 = x + io_cell_v_x1; el.x2 = el.x1 - wire_length_long; } el.y1 = y + io_cell_v_y1 + 8 * io_cell_gap + wire_distance * (num + 1); el.y2 = el.y1; g.push_back(el); } else if (wire_type == id_WIRE_TYPE_EBR) { el.x1 = x + slice_x1 - wire_length; el.x2 = x + slice_x1; el.y1 = y + slice_y2 - wire_distance * (tilewire - TILE_WIRE_JADA0_EBR + 1) + 3 * slice_pitch; el.y2 = el.y1; g.push_back(el); } else if (wire_type == id_WIRE_TYPE_MULT18) { el.x1 = x + slice_x1 - wire_length; el.x2 = x + slice_x1; el.y1 = y + slice_y2 - wire_distance_small * (tilewire - TILE_WIRE_JCLK0_MULT18 + 1) + 3 * slice_pitch; el.y2 = el.y1; g.push_back(el); } else if (wire_type == id_WIRE_TYPE_ALU54) { int num = (tilewire - TILE_WIRE_JCLK0_ALU54) % 225; int group = (tilewire - TILE_WIRE_JCLK0_ALU54) / 225; if (group == 0) { el.x1 = x + slice_x1 - wire_length; el.x2 = x + slice_x1; } else { el.x1 = x + slice_x2_wide + wire_length; el.x2 = x + slice_x2_wide; } el.y1 = y + slice_y2 - wire_distance_small * (num + 1) + 3 * slice_pitch; el.y2 = el.y1; g.push_back(el); } else if (wire_type == id_WIRE_TYPE_PLL) { el.x1 = x + slice_x1 - wire_length; el.x2 = x + slice_x1; el.y1 = y + slice_y2 - wire_distance * (tilewire - TILE_WIRE_CLKI_PLL + 1); el.y2 = el.y1; g.push_back(el); } else if (wire_type == id_WIRE_TYPE_GSR) { el.x1 = x + slice_x1 - wire_length; el.x2 = x + slice_x1; el.y1 = y + slice_y2 - wire_distance * (tilewire - TILE_WIRE_JCLK_GSR + 1); el.y2 = el.y1; g.push_back(el); } else if (wire_type == id_WIRE_TYPE_JTAG) { el.x1 = x + slice_x1 - wire_length; el.x2 = x + slice_x1; el.y1 = y + slice_y2 - wire_distance * (tilewire - TILE_WIRE_JJCE1_JTAG + 1) + 1 * slice_pitch; el.y2 = el.y1; g.push_back(el); } else if (wire_type == id_WIRE_TYPE_OSC) { el.x1 = x + slice_x1 - wire_length; el.x2 = x + slice_x1; el.y1 = y + slice_y2 - wire_distance * (tilewire - TILE_WIRE_SEDSTDBY_OSC + 1) + 2 * slice_pitch; el.y2 = el.y1; g.push_back(el); } else if (wire_type == id_WIRE_TYPE_SED) { el.x1 = x + slice_x1 - wire_length; el.x2 = x + slice_x1; el.y1 = y + slice_y2 - wire_distance * (tilewire - TILE_WIRE_SEDSTDBY_SED + 1) + 3 * slice_pitch; el.y2 = el.y1; g.push_back(el); } else if (wire_type == id_WIRE_TYPE_DTR) { el.x1 = x + slice_x1 - wire_length; el.x2 = x + slice_x1; el.y1 = y + slice_y2 - wire_distance * (tilewire - TILE_WIRE_JSTARTPULSE_DTR + 1); el.y2 = el.y1; g.push_back(el); } else if (wire_type == id_WIRE_TYPE_EXTREF) { el.x1 = x + slice_x1 - wire_length; el.x2 = x + slice_x1; el.y1 = y + slice_y2 - wire_distance * (tilewire - TILE_WIRE_REFCLKP_EXTREF + 1) + 1 * slice_pitch; el.y2 = el.y1; g.push_back(el); } else if (wire_type == id_WIRE_TYPE_DCU) { el.x1 = x + slice_x1 - wire_length; el.x2 = x + slice_x1; el.y1 = y + slice_y2 - wire_distance * (tilewire - TILE_WIRE_CH0_RX_REFCLK_DCU + 1) + 0 * slice_pitch; el.y2 = el.y1; g.push_back(el); } else if (wire_type == id_WIRE_TYPE_PCSCLKDIV) { int num = (tilewire - TILE_WIRE_CLKI_PCSCLKDIV1) % 7; int group = 1 - (tilewire - TILE_WIRE_CLKI_PCSCLKDIV1) / 7; el.x1 = x + slice_x1 - wire_length; el.x2 = x + slice_x1; el.y1 = y + slice_y2 - wire_distance * (num + 1) + group * slice_pitch; el.y2 = el.y1; g.push_back(el); } } void setSource(GraphicElement &el, int x, int y, int w, int h, WireId src, IdString src_type, GfxTileWireId src_id) { if (src_type == id_WIRE_TYPE_H00) { int group = (src_id - TILE_WIRE_H00L0000) / 2; el.y1 = y + switchbox_y1 + wire_distance * (8 - ((src_id - TILE_WIRE_H00L0000) % 2) * 4); if (group) { el.x1 = x + switchbox_x2; } else { el.x1 = x + switchbox_x1; } } if (src_type == id_WIRE_TYPE_H01) { if (x == src.location.x) el.x1 = x + switchbox_x1; else el.x1 = x + switchbox_x2; el.y1 = y + switchbox_y1 + wire_distance * (10 + src_id - TILE_WIRE_H01E0001); } if (src_type == id_WIRE_TYPE_H02) { el.x1 = x + switchbox_x1 + wire_distance * (20 + (src_id - TILE_WIRE_H02W0701) + 20 * (src.location.x % 3)); el.y1 = y + switchbox_y1; } if (src_type == id_WIRE_TYPE_H06) { el.x1 = x + switchbox_x1 + wire_distance * (96 + (src_id - TILE_WIRE_H06W0303) + 10 * (src.location.x % 9)); el.y1 = y + switchbox_y1; } if (src_type == id_WIRE_TYPE_V00) { int group = (src_id - TILE_WIRE_V00T0000) / 2; el.x1 = x + switchbox_x2 - wire_distance * (8 - ((src_id - TILE_WIRE_V00T0000) % 2) * 4); if (group) { el.y1 = y + switchbox_y1; } else { el.y1 = y + switchbox_y2; } } if (src_type == id_WIRE_TYPE_V01) { el.x1 = x + switchbox_x1 + wire_distance * (10 + src_id - TILE_WIRE_V01N0001); if (y == src.location.y) el.y1 = y + switchbox_y2; else el.y1 = y + switchbox_y1; } if (src_type == id_WIRE_TYPE_V02) { el.x1 = x + switchbox_x1; el.y1 = y + switchbox_y1 + wire_distance * (20 + (src_id - TILE_WIRE_V02N0701) + 20 * (src.location.y % 3)); } if (src_type == id_WIRE_TYPE_V06) { el.x1 = x + switchbox_x1; el.y1 = y + switchbox_y1 + wire_distance * (96 + (src_id - TILE_WIRE_V06N0303) + 10 * (src.location.y % 9)); } if (src_type == id_WIRE_TYPE_NONE) { if (src_id >= TILE_WIRE_CLK0 && src_id <= TILE_WIRE_LSR1) { el.x1 = x + switchbox_x2; el.y1 = y + slice_y2 - wire_distance * (src_id - TILE_WIRE_CLK0 - 5) + 3 * slice_pitch; } if (src_id >= TILE_WIRE_FCO && src_id <= TILE_WIRE_FCI) { int gap = (src_id - TILE_WIRE_FCO) / 24; el.x1 = src.location.x + switchbox_x2; el.y1 = src.location.y + slice_y2 - wire_distance * (src_id - TILE_WIRE_FCO + 1 + gap * 2) + 3 * slice_pitch; } if (src_id >= TILE_WIRE_JCE0 && src_id <= TILE_WIRE_JQ7) { el.x1 = src.location.x + switchbox_x2 + wire_length; el.y1 = src.location.y + slice_y2 - wire_distance * (src_id - TILE_WIRE_JCE0 + 1) + 3 * slice_pitch; } if (src_id >= TILE_WIRE_JDIA && src_id <= TILE_WIRE_ECLKD) { bool top = (src.location.y == (h - 1)); el.x1 = src.location.x + 0.5f + wire_length; if (top) el.y1 = src.location.y + 1 - (slice_y2 - wire_distance * (src_id - TILE_WIRE_JDIA + 1) + 3 * slice_pitch); else el.y1 = src.location.y + slice_y2 - wire_distance * (src_id - TILE_WIRE_JDIA + 1) + 3 * slice_pitch; } } if (src_type == id_WIRE_TYPE_IOLOGIC) { int gap = 7 - (src_id - TILE_WIRE_JLOADND_IOLOGIC) / 42; int num = (src_id - TILE_WIRE_JLOADND_IOLOGIC) % 42; if (src.location.x == 0) { el.x1 = src.location.x + 1 - io_cell_v_x1 + wire_length_long; } else { el.x1 = src.location.x + io_cell_v_x1 - wire_length_long; } el.y1 = src.location.y + io_cell_v_y1 + gap * io_cell_gap + wire_distance * (num + 1); } if (src_type == id_WIRE_TYPE_SIOLOGIC) { int gap = (src_id - TILE_WIRE_JLOADNB_SIOLOGIC) / 20; int num = (src_id - TILE_WIRE_JLOADNB_SIOLOGIC) % 20; el.x1 = src.location.x + io_cell_h_x1 + (5 - gap) * io_cell_gap + wire_distance * (num + 1); if (src.location.y == h - 1) { el.y1 = src.location.y + 1 - io_cell_h_y2 - wire_length_long; } else { el.y1 = src.location.y + io_cell_h_y2 + wire_length_long; } } if (src_type == id_WIRE_TYPE_PIO) { bool top_bottom = (src.location.y == 0 || src.location.y == (h - 1)); int gap = 3 - (src_id - TILE_WIRE_PADDOD_PIO) / 7; int num = (src_id - TILE_WIRE_PADDOD_PIO) % 7; if (top_bottom) { el.x1 = src.location.x + io_cell_h_x1 + (gap + 2) * io_cell_gap + wire_distance * (num + 1); if (src.location.y == h - 1) { el.y1 = src.location.y + 1 - io_cell_h_y2 - wire_length_long; } else { el.y1 = src.location.y + 1 - io_cell_h_y2 + wire_length_long; } } else { if (x == 0) { el.x1 = src.location.x + 1 - io_cell_v_x1 + wire_length_long; } else { el.x1 = src.location.x + io_cell_v_x1 - wire_length_long; } el.y1 = src.location.y + io_cell_v_y1 + gap * io_cell_gap + wire_distance * (num + 1); } } if (src_type == id_WIRE_TYPE_EBR) { el.x1 = src.location.x + slice_x1 - wire_length; el.y1 = src.location.y + slice_y2 - wire_distance * (src_id - TILE_WIRE_JADA0_EBR + 1) + 3 * slice_pitch; } if (src_type == id_WIRE_TYPE_MULT18) { el.x1 = src.location.x + slice_x1 - wire_length; el.y1 = src.location.y + slice_y2 - wire_distance_small * (src_id - TILE_WIRE_JCLK0_MULT18 + 1) + 3 * slice_pitch; } if (src_type == id_WIRE_TYPE_ALU54) { int num = (src_id - TILE_WIRE_JCLK0_ALU54) % 225; int group = (src_id - TILE_WIRE_JCLK0_ALU54) / 225; if (group == 0) { el.x1 = src.location.x + slice_x1 - wire_length; } else { el.x1 = src.location.x + slice_x2_wide + wire_length; } el.y1 = src.location.y + slice_y2 - wire_distance_small * (num + 1) + 3 * slice_pitch; } if (src_type == id_WIRE_TYPE_PLL) { el.x1 = src.location.x + slice_x1 - wire_length; el.y1 = src.location.y + slice_y2 - wire_distance * (src_id - TILE_WIRE_CLKI_PLL + 1); } if (src_type == id_WIRE_TYPE_GSR) { el.x1 = src.location.x + slice_x1 - wire_length; el.y1 = src.location.y + slice_y2 - wire_distance * (src_id - TILE_WIRE_JCLK_GSR + 1); } if (src_type == id_WIRE_TYPE_JTAG) { el.x1 = src.location.x + slice_x1 - wire_length; el.y1 = src.location.y + slice_y2 - wire_distance * (src_id - TILE_WIRE_JJCE1_JTAG + 1) + 1 * slice_pitch; } if (src_type == id_WIRE_TYPE_OSC) { el.x1 = src.location.x + slice_x1 - wire_length; el.y1 = src.location.y + slice_y2 - wire_distance * (src_id - TILE_WIRE_SEDSTDBY_OSC + 1) + 2 * slice_pitch; } if (src_type == id_WIRE_TYPE_SED) { el.x1 = src.location.x + slice_x1 - wire_length; el.y1 = src.location.y + slice_y2 - wire_distance * (src_id - TILE_WIRE_SEDSTDBY_SED + 1) + 3 * slice_pitch; } if (src_type == id_WIRE_TYPE_DTR) { el.x1 = src.location.x + slice_x1 - wire_length; el.y1 = src.location.y + slice_y2 - wire_distance * (src_id - TILE_WIRE_JSTARTPULSE_DTR + 1); } if (src_type == id_WIRE_TYPE_EXTREF) { el.x1 = src.location.x + slice_x1 - wire_length; el.y1 = src.location.y + slice_y2 - wire_distance * (src_id - TILE_WIRE_REFCLKP_EXTREF + 1) + 1 * slice_pitch; } if (src_type == id_WIRE_TYPE_DCU) { el.x1 = src.location.x + slice_x1 - wire_length; el.y1 = src.location.y + slice_y2 - wire_distance * (src_id - TILE_WIRE_CH0_RX_REFCLK_DCU + 1) + 0 * slice_pitch; } if (src_type == id_WIRE_TYPE_PCSCLKDIV) { int num = (src_id - TILE_WIRE_CLKI_PCSCLKDIV1) % 7; int group = 1 - (src_id - TILE_WIRE_CLKI_PCSCLKDIV1) / 7; el.x1 = src.location.x + slice_x1 - wire_length; el.y1 = src.location.y + slice_y2 - wire_distance * (num + 1) + group * slice_pitch; } if (src_type == id_WIRE_TYPE_DQS) { int num = (src_id - TILE_WIRE_DDRDEL_DQS); if (src.location.x == 0) { el.x1 = src.location.x + 1 - io_cell_v_x1 + wire_length_long; } else { el.x1 = src.location.x + io_cell_v_x1 - wire_length_long; } el.y1 = src.location.y + io_cell_v_y1 + 8 * io_cell_gap + wire_distance * (num + 1); } if (src_type == id_WIRE_TYPE_DDRDLL) { int num = (src_id - TILE_WIRE_DDRDEL_DDRDLL); el.x1 = src.location.x + io_cell_h_x1 + dll_cell_x1 + wire_distance * (num + 1); if (src.location.y == h - 1) { el.y1 = src.location.y + dll_cell_y1 - wire_length_long; } else { el.y1 = src.location.y + dll_cell_y2 + wire_length_long; } } if (src_type == id_WIRE_TYPE_CCLK) { int num = (src_id - TILE_WIRE_JPADDI_CCLK); el.x1 = src.location.x + slice_x1 + wire_distance * (num + 1); el.y1 = src.location.y + slice_y2 - 1 * slice_pitch - wire_length_long; } if (src_type == id_WIRE_TYPE_G_HPBX) { el.x1 = x + switchbox_x1 + wire_distance * (200 + (src_id - TILE_WIRE_G_HPBX0000)); el.y1 = y + switchbox_y1; } } void setDestination(GraphicElement &el, int x, int y, int w, int h, WireId dst, IdString dst_type, GfxTileWireId dst_id) { if (dst_type == id_WIRE_TYPE_H00) { int group = (dst_id - TILE_WIRE_H00L0000) / 2; el.y2 = y + switchbox_y1 + wire_distance * (8 - ((dst_id - TILE_WIRE_H00L0000) % 2) * 4); if (group) { el.x2 = x + switchbox_x2; } else { el.x2 = x + switchbox_x1; } } if (dst_type == id_WIRE_TYPE_H01) { if (x == dst.location.x) el.x2 = x + switchbox_x1; else el.x2 = x + switchbox_x2; el.y2 = y + switchbox_y1 + wire_distance * (10 + dst_id - TILE_WIRE_H01E0001); } if (dst_type == id_WIRE_TYPE_H02) { el.x2 = x + switchbox_x1 + wire_distance * (20 + (dst_id - TILE_WIRE_H02W0701) + 20 * (dst.location.x % 3)); el.y2 = y + switchbox_y1; } if (dst_type == id_WIRE_TYPE_H06) { el.x2 = x + switchbox_x1 + wire_distance * (96 + (dst_id - TILE_WIRE_H06W0303) + 10 * (dst.location.x % 9)); el.y2 = y + switchbox_y1; } if (dst_type == id_WIRE_TYPE_V00) { int group = (dst_id - TILE_WIRE_V00T0000) / 2; el.x2 = x + switchbox_x2 - wire_distance * (8 - ((dst_id - TILE_WIRE_V00T0000) % 2) * 4); if (group) { el.y2 = y + switchbox_y1; } else { el.y2 = y + switchbox_y2; } } if (dst_type == id_WIRE_TYPE_V01) { el.x2 = x + switchbox_x1 + wire_distance * (10 + dst_id - TILE_WIRE_V01N0001); if (y == dst.location.y) el.y2 = y + switchbox_y2; else el.y2 = y + switchbox_y1; } if (dst_type == id_WIRE_TYPE_V02) { el.x2 = x + switchbox_x1; el.y2 = y + switchbox_y1 + wire_distance * (20 + (dst_id - TILE_WIRE_V02N0701) + 20 * (dst.location.y % 3)); } if (dst_type == id_WIRE_TYPE_V06) { el.x2 = x + switchbox_x1; el.y2 = y + switchbox_y1 + wire_distance * (96 + (dst_id - TILE_WIRE_V06N0303) + 10 * (dst.location.y % 9)); } if (dst_type == id_WIRE_TYPE_NONE) { if (dst_id >= TILE_WIRE_CLK0 && dst_id <= TILE_WIRE_LSR1) { el.x2 = x + switchbox_x2; el.y2 = y + slice_y2 - wire_distance * (dst_id - TILE_WIRE_CLK0 - 5) + 3 * slice_pitch; } if (dst_id >= TILE_WIRE_FCO && dst_id <= TILE_WIRE_FCI) { int gap = (dst_id - TILE_WIRE_FCO) / 24; el.x2 = x + switchbox_x2; el.y2 = y + slice_y2 - wire_distance * (dst_id - TILE_WIRE_FCO + 1 + gap * 2) + 3 * slice_pitch; } if (dst_id >= TILE_WIRE_JCE0 && dst_id <= TILE_WIRE_JQ7) { el.x2 = dst.location.x + switchbox_x2; el.y2 = dst.location.y + slice_y2 - wire_distance * (dst_id - TILE_WIRE_JCE0 + 1) + 3 * slice_pitch; } if (dst_id >= TILE_WIRE_JDIA && dst_id <= TILE_WIRE_ECLKD) { bool top = (dst.location.y == (h - 1)); el.x2 = dst.location.x + 0.5f; if (top) el.y2 = dst.location.y + 1 - (slice_y2 - wire_distance * (dst_id - TILE_WIRE_JDIA + 1) + 3 * slice_pitch); else el.y2 = dst.location.y + slice_y2 - wire_distance * (dst_id - TILE_WIRE_JDIA + 1) + 3 * slice_pitch; } } if (dst_type == id_WIRE_TYPE_IOLOGIC) { int gap = 7 - (dst_id - TILE_WIRE_JLOADND_IOLOGIC) / 42; int num = (dst_id - TILE_WIRE_JLOADND_IOLOGIC) % 42; if (dst.location.x == 0) { el.x2 = dst.location.x + 1 - io_cell_v_x1 + wire_length_long; } else { el.x2 = dst.location.x + io_cell_v_x1 - wire_length_long; } el.y2 = dst.location.y + io_cell_v_y1 + gap * io_cell_gap + wire_distance * (num + 1); } if (dst_type == id_WIRE_TYPE_SIOLOGIC) { int gap = (dst_id - TILE_WIRE_JLOADNB_SIOLOGIC) / 20; int num = (dst_id - TILE_WIRE_JLOADNB_SIOLOGIC) % 20; el.x2 = dst.location.x + io_cell_h_x1 + (5 - gap) * io_cell_gap + wire_distance * (num + 1); if (dst.location.y == h - 1) { el.y2 = dst.location.y + 1 - io_cell_h_y2 - wire_length_long; } else { el.y2 = dst.location.y + io_cell_h_y2 + wire_length_long; } } if (dst_type == id_WIRE_TYPE_PIO) { bool top_bottom = (dst.location.y == 0 || dst.location.y == (h - 1)); int gap = 3 - (dst_id - TILE_WIRE_PADDOD_PIO) / 7; int num = (dst_id - TILE_WIRE_PADDOD_PIO) % 7; if (top_bottom) { el.x2 = dst.location.x + io_cell_h_x1 + (gap + 2) * io_cell_gap + wire_distance * (num + 1); if (dst.location.y == h - 1) { el.y2 = dst.location.y + 1 - io_cell_h_y2 - wire_length_long; } else { el.y2 = dst.location.y + 1 - io_cell_h_y2 + wire_length_long; } } else { if (x == 0) { el.x2 = dst.location.x + 1 - io_cell_v_x1 + wire_length_long; } else { el.x2 = dst.location.x + io_cell_v_x1 - wire_length_long; } el.y2 = dst.location.y + io_cell_v_y1 + gap * io_cell_gap + wire_distance * (num + 1); } } if (dst_type == id_WIRE_TYPE_EBR) { el.x2 = dst.location.x + slice_x1 - wire_length; el.y2 = dst.location.y + slice_y2 - wire_distance * (dst_id - TILE_WIRE_JADA0_EBR + 1) + 3 * slice_pitch; } if (dst_type == id_WIRE_TYPE_MULT18) { el.x2 = dst.location.x + slice_x1 - wire_length; el.y2 = dst.location.y + slice_y2 - wire_distance_small * (dst_id - TILE_WIRE_JCLK0_MULT18 + 1) + 3 * slice_pitch; } if (dst_type == id_WIRE_TYPE_ALU54) { int num = (dst_id - TILE_WIRE_JCLK0_ALU54) % 225; int group = (dst_id - TILE_WIRE_JCLK0_ALU54) / 225; if (group == 0) { el.x2 = dst.location.x + slice_x1 - wire_length; } else { el.x2 = dst.location.x + slice_x2_wide + wire_length; } el.y2 = dst.location.y + slice_y2 - wire_distance_small * (num + 1) + 3 * slice_pitch; } if (dst_type == id_WIRE_TYPE_PLL) { el.x2 = dst.location.x + slice_x1 - wire_length; el.y2 = dst.location.y + slice_y2 - wire_distance * (dst_id - TILE_WIRE_CLKI_PLL + 1); } if (dst_type == id_WIRE_TYPE_GSR) { el.x2 = dst.location.x + slice_x1 - wire_length; el.y2 = dst.location.y + slice_y2 - wire_distance * (dst_id - TILE_WIRE_JCLK_GSR + 1); } if (dst_type == id_WIRE_TYPE_JTAG) { el.x2 = dst.location.x + slice_x1 - wire_length; el.y2 = dst.location.y + slice_y2 - wire_distance * (dst_id - TILE_WIRE_JJCE1_JTAG + 1) + 1 * slice_pitch; } if (dst_type == id_WIRE_TYPE_OSC) { el.x2 = dst.location.x + slice_x1 - wire_length; el.y2 = dst.location.y + slice_y2 - wire_distance * (dst_id - TILE_WIRE_SEDSTDBY_OSC + 1) + 2 * slice_pitch; } if (dst_type == id_WIRE_TYPE_SED) { el.x2 = dst.location.x + slice_x1 - wire_length; el.y2 = dst.location.y + slice_y2 - wire_distance * (dst_id - TILE_WIRE_SEDSTDBY_SED + 1) + 3 * slice_pitch; } if (dst_type == id_WIRE_TYPE_DTR) { el.x2 = dst.location.x + slice_x1 - wire_length; el.y2 = dst.location.y + slice_y2 - wire_distance * (dst_id - TILE_WIRE_JSTARTPULSE_DTR + 1); } if (dst_type == id_WIRE_TYPE_EXTREF) { el.x2 = dst.location.x + slice_x1 - wire_length; el.y2 = dst.location.y + slice_y2 - wire_distance * (dst_id - TILE_WIRE_REFCLKP_EXTREF + 1) + 1 * slice_pitch; } if (dst_type == id_WIRE_TYPE_DCU) { el.x2 = dst.location.x + slice_x1 - wire_length; el.y2 = dst.location.y + slice_y2 - wire_distance * (dst_id - TILE_WIRE_CH0_RX_REFCLK_DCU + 1) + 0 * slice_pitch; } if (dst_type == id_WIRE_TYPE_PCSCLKDIV) { int num = (dst_id - TILE_WIRE_CLKI_PCSCLKDIV1) % 7; int group = 1 - (dst_id - TILE_WIRE_CLKI_PCSCLKDIV1) / 7; el.x2 = dst.location.x + slice_x1 - wire_length; el.y2 = dst.location.y + slice_y2 - wire_distance * (num + 1) + group * slice_pitch; } if (dst_type == id_WIRE_TYPE_DQS) { int num = (dst_id - TILE_WIRE_DDRDEL_DQS); if (dst.location.x == 0) { el.x2 = dst.location.x + 1 - io_cell_v_x1 + wire_length_long; } else { el.x2 = dst.location.x + io_cell_v_x1 - wire_length_long; } el.y2 = dst.location.y + io_cell_v_y1 + 8 * io_cell_gap + wire_distance * (num + 1); } if (dst_type == id_WIRE_TYPE_DDRDLL) { int num = (dst_id - TILE_WIRE_DDRDEL_DDRDLL); el.x2 = dst.location.x + io_cell_h_x1 + dll_cell_x1 + wire_distance * (num + 1); if (dst.location.y == h - 1) { el.y2 = dst.location.y + dll_cell_y1 - wire_length_long; } else { el.y2 = dst.location.y + dll_cell_y2 + wire_length_long; } } if (dst_type == id_WIRE_TYPE_CCLK) { int num = (dst_id - TILE_WIRE_JPADDI_CCLK); el.x2 = dst.location.x + slice_x1 + wire_distance * (num + 1); el.y2 = dst.location.y + slice_y2 - 1 * slice_pitch - wire_length_long; } if (dst_type == id_WIRE_TYPE_G_HPBX) { el.x2 = x + switchbox_x1 + wire_distance * (200 + (dst_id - TILE_WIRE_G_HPBX0000)); el.y2 = y + switchbox_y1; } } void straightLine(std::vector &g, GraphicElement &el, int x, int y, int w, int h, WireId src, IdString src_type, GfxTileWireId src_id, WireId dst, IdString dst_type, GfxTileWireId dst_id) { setSource(el, x, y, w, h, src, src_type, src_id); setDestination(el, x, y, w, h, dst, dst_type, dst_id); g.push_back(el); } void lutPermPip(std::vector &g, GraphicElement &el, int x, int y, int w, int h, WireId src, IdString src_type, GfxTileWireId src_id, WireId dst, IdString dst_type, GfxTileWireId dst_id) { int gap = (src_id - TILE_WIRE_FCO) / 24; el.x1 = src.location.x + slice_x1 - wire_length_lut; el.y1 = src.location.y + slice_y2 - wire_distance * (src_id - TILE_WIRE_FCO + 1 + gap * 2) + 3 * slice_pitch; el.x2 = src.location.x + slice_x1 - wire_length; el.y2 = src.location.y + slice_y2 - wire_distance * (dst_id - TILE_WIRE_FCO_SLICE + 1 + gap * 2) + 3 * slice_pitch; g.push_back(el); } void toSameSideHor(std::vector &g, GraphicElement &el, int x, int y, int w, int h, WireId src, IdString src_type, GfxTileWireId src_id, WireId dst, IdString dst_type, GfxTileWireId dst_id, GraphicElement::style_t style, int idx) { int sign = (src_type == dst_type) ? 1 : -1; setSource(el, x, y, w, h, src, src_type, src_id); el.x2 = el.x1; el.y2 = y + switchbox_y1 + (switchbox_y2 - switchbox_y1) / 2 + sign * wire_distance * idx; g.push_back(el); GraphicElement el2; el2.type = GraphicElement::TYPE_ARROW; el2.style = style; setDestination(el2, x, y, w, h, dst, dst_type, dst_id); el.x1 = el2.x2; el.y1 = el.y2; g.push_back(el); el2.x1 = el.x1; el2.y1 = el.y1; g.push_back(el2); } void toSameSideVer(std::vector &g, GraphicElement &el, int x, int y, int w, int h, WireId src, IdString src_type, GfxTileWireId src_id, WireId dst, IdString dst_type, GfxTileWireId dst_id, GraphicElement::style_t style, int idx) { int sign = (src_type == dst_type) ? 1 : -1; setSource(el, x, y, w, h, src, src_type, src_id); el.x2 = x + switchbox_x1 + (switchbox_x2 - switchbox_x1) / 2 + sign * wire_distance * idx; el.y2 = el.y1; g.push_back(el); GraphicElement el2; el2.type = GraphicElement::TYPE_ARROW; el2.style = style; setDestination(el2, x, y, w, h, dst, dst_type, dst_id); el.x1 = el.x2; el.y1 = el2.y2; g.push_back(el); el2.x1 = el.x1; el2.y1 = el.y1; g.push_back(el2); } void toSameSideH1Ver(std::vector &g, GraphicElement &el, int x, int y, int w, int h, WireId src, IdString src_type, GfxTileWireId src_id, WireId dst, IdString dst_type, GfxTileWireId dst_id, GraphicElement::style_t style, int idx) { setSource(el, x, y, w, h, src, src_type, src_id); el.x2 = x + switchbox_x1 + (switchbox_x2 - switchbox_x1) / 2 - wire_distance * idx; el.y2 = el.y1; g.push_back(el); GraphicElement el2; el2.type = GraphicElement::TYPE_ARROW; el2.style = style; setDestination(el2, x, y, w, h, dst, dst_type, dst_id); el.x1 = el.x2; el.y1 = el2.y2; g.push_back(el); el2.x1 = el.x1; el2.y1 = el.y1; g.push_back(el2); } void toSameSideH1Hor(std::vector &g, GraphicElement &el, int x, int y, int w, int h, WireId src, IdString src_type, GfxTileWireId src_id, WireId dst, IdString dst_type, GfxTileWireId dst_id, GraphicElement::style_t style, int idx) { setSource(el, x, y, w, h, src, src_type, src_id); GraphicElement el2; el2.type = GraphicElement::TYPE_ARROW; el2.style = style; setDestination(el2, x, y, w, h, dst, dst_type, dst_id); if (dst_type == id_WIRE_TYPE_H01 || src_type == id_WIRE_TYPE_V01 || dst_type == id_WIRE_TYPE_H00) { el.x2 = el.x1; el.y2 = el2.y2; g.push_back(el); } else { el.x2 = el2.x2; el.y2 = el.y1; g.push_back(el); } el2.x1 = el.x2; el2.y1 = el.y2; g.push_back(el2); } void toSameSideV1Ver(std::vector &g, GraphicElement &el, int x, int y, int w, int h, WireId src, IdString src_type, GfxTileWireId src_id, WireId dst, IdString dst_type, GfxTileWireId dst_id, GraphicElement::style_t style, int idx) { setSource(el, x, y, w, h, src, src_type, src_id); el.x2 = el.x1; el.y2 = y + switchbox_y1 + (switchbox_y2 - switchbox_y1) / 2 - wire_distance * idx; g.push_back(el); GraphicElement el2; el2.type = GraphicElement::TYPE_ARROW; el2.style = style; setDestination(el2, x, y, w, h, dst, dst_type, dst_id); el.x1 = el2.x2; el.y1 = el.y2; g.push_back(el); el2.x1 = el.x1; el2.y1 = el.y1; g.push_back(el2); } void gfxTilePip(std::vector &g, int x, int y, int w, int h, WireId src, IdString src_type, GfxTileWireId src_id, WireId dst, IdString dst_type, GfxTileWireId dst_id, GraphicElement::style_t style) { GraphicElement el; el.type = GraphicElement::TYPE_ARROW; el.style = style; // To H00 if (src_type == id_WIRE_TYPE_V02 && dst_type == id_WIRE_TYPE_H00) { toSameSideH1Ver(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, dst_id - TILE_WIRE_H00L0000 + 30); } if (src_type == id_WIRE_TYPE_H02 && dst_type == id_WIRE_TYPE_H00) { straightLine(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id); } // To H01 if (src_type == id_WIRE_TYPE_H06 && dst_type == id_WIRE_TYPE_H01) { toSameSideH1Hor(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, dst_id - TILE_WIRE_H01E0001); } // To H02 if (src_type == id_WIRE_TYPE_H01 && dst_type == id_WIRE_TYPE_H02) { toSameSideH1Hor(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, dst_id - TILE_WIRE_H02W0701); } if (src_type == id_WIRE_TYPE_H02 && dst_type == id_WIRE_TYPE_H02) { toSameSideHor(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, src_id - TILE_WIRE_H02W0701); } if (src_type == id_WIRE_TYPE_H06 && dst_type == id_WIRE_TYPE_H02) { toSameSideHor(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, src_id - TILE_WIRE_H06W0303); } if (src_type == id_WIRE_TYPE_V01 && dst_type == id_WIRE_TYPE_H02) { if (y == src.location.y) { straightLine(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id); } else { toSameSideV1Ver(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, dst_id - TILE_WIRE_H02W0701); } } if (src_type == id_WIRE_TYPE_V02 && dst_type == id_WIRE_TYPE_H02) { straightLine(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id); } if (src_type == id_WIRE_TYPE_V06 && dst_type == id_WIRE_TYPE_H02) { straightLine(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id); } // To H06 if (src_type == id_WIRE_TYPE_H01 && dst_type == id_WIRE_TYPE_H06) { toSameSideH1Hor(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, dst_id - TILE_WIRE_H06W0303); } if (src_type == id_WIRE_TYPE_H02 && dst_type == id_WIRE_TYPE_H06) { toSameSideHor(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, src_id - TILE_WIRE_H02W0701); } if (src_type == id_WIRE_TYPE_H06 && dst_type == id_WIRE_TYPE_H06) { toSameSideHor(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, src_id - TILE_WIRE_H06W0303); } if (src_type == id_WIRE_TYPE_V01 && dst_type == id_WIRE_TYPE_H06) { if (y == src.location.y) { straightLine(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id); } else { toSameSideV1Ver(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, dst_id - TILE_WIRE_H06W0303); } } if (src_type == id_WIRE_TYPE_V06 && dst_type == id_WIRE_TYPE_H06) { straightLine(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id); } // To V00 if (src_type == id_WIRE_TYPE_V02 && dst_type == id_WIRE_TYPE_V00) { straightLine(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id); } if (src_type == id_WIRE_TYPE_H02 && dst_type == id_WIRE_TYPE_V00) { toSameSideV1Ver(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, src_id - TILE_WIRE_H02W0701 + 20); } // To V01 if (src_type == id_WIRE_TYPE_V06 && dst_type == id_WIRE_TYPE_V01) { toSameSideH1Hor(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, dst_id - TILE_WIRE_V01N0001); } // To V02 if (src_type == id_WIRE_TYPE_H01 && dst_type == id_WIRE_TYPE_V02) { if (x == src.location.x) { toSameSideH1Ver(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, dst_id - TILE_WIRE_V02N0701); } else { straightLine(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id); } } if (src_type == id_WIRE_TYPE_H02 && dst_type == id_WIRE_TYPE_V02) { straightLine(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id); } if (src_type == id_WIRE_TYPE_H06 && dst_type == id_WIRE_TYPE_V02) { straightLine(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id); } if (src_type == id_WIRE_TYPE_V01 && dst_type == id_WIRE_TYPE_V02) { toSameSideH1Hor(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, dst_id - TILE_WIRE_V02N0701); } if (src_type == id_WIRE_TYPE_V02 && dst_type == id_WIRE_TYPE_V02) { toSameSideVer(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, src_id - TILE_WIRE_V02N0701); } if (src_type == id_WIRE_TYPE_V06 && dst_type == id_WIRE_TYPE_V02) { toSameSideVer(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, src_id - TILE_WIRE_V06N0303); } // To V06 if (src_type == id_WIRE_TYPE_H01 && dst_type == id_WIRE_TYPE_V06) { if (x == src.location.x) { toSameSideH1Ver(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, dst_id - TILE_WIRE_V06N0303); } else { straightLine(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id); } } if (src_type == id_WIRE_TYPE_H06 && dst_type == id_WIRE_TYPE_V06) { straightLine(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id); } if (src_type == id_WIRE_TYPE_V01 && dst_type == id_WIRE_TYPE_V06) { toSameSideH1Hor(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, dst_id - TILE_WIRE_V06N0303); } if (src_type == id_WIRE_TYPE_V02 && dst_type == id_WIRE_TYPE_V06) { toSameSideVer(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, src_id - TILE_WIRE_V02N0701); } if (src_type == id_WIRE_TYPE_V06 && dst_type == id_WIRE_TYPE_V06) { toSameSideVer(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, src_id - TILE_WIRE_V06N0303); } if (src_type == id_WIRE_TYPE_H00 && dst_type == id_WIRE_TYPE_NONE && (dst_id >= TILE_WIRE_FCO && dst_id <= TILE_WIRE_FCI)) { toSameSideH1Ver(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, dst_id - TILE_WIRE_FCO); } if (src_type == id_WIRE_TYPE_H00 && dst_type == id_WIRE_TYPE_NONE && (dst_id >= TILE_WIRE_JCE0 && dst_id <= TILE_WIRE_JQ7)) { toSameSideH1Ver(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, dst_id - TILE_WIRE_JCE0); } if (src_type == id_WIRE_TYPE_H01 && dst_type == id_WIRE_TYPE_NONE && (dst_id >= TILE_WIRE_FCO && dst_id <= TILE_WIRE_FCI)) { toSameSideH1Ver(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, dst_id - TILE_WIRE_FCO); } if (src_type == id_WIRE_TYPE_H01 && dst_type == id_WIRE_TYPE_NONE && (dst_id >= TILE_WIRE_JCE0 && dst_id <= TILE_WIRE_JQ7)) { toSameSideH1Ver(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, dst_id - TILE_WIRE_JCE0); } if ((src_type.in(id_WIRE_TYPE_H02, id_WIRE_TYPE_V00, id_WIRE_TYPE_V01, id_WIRE_TYPE_V02)) && dst_type == id_WIRE_TYPE_NONE && ((dst_id >= TILE_WIRE_FCO && dst_id <= TILE_WIRE_FCI) || (dst_id >= TILE_WIRE_JCE0 && dst_id <= TILE_WIRE_JQ7))) { straightLine(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id); } if ((dst_type.in(id_WIRE_TYPE_H02, id_WIRE_TYPE_V00, id_WIRE_TYPE_V01, id_WIRE_TYPE_V02)) && src_type == id_WIRE_TYPE_NONE && ((src_id >= TILE_WIRE_FCO && src_id <= TILE_WIRE_FCI) || (src_id >= TILE_WIRE_JCE0 && src_id <= TILE_WIRE_JQ7))) { straightLine(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id); } if (dst_type == id_WIRE_TYPE_NONE && (dst_id >= TILE_WIRE_FCO && dst_id <= TILE_WIRE_FCI) && src_type == id_WIRE_TYPE_NONE && (src_id >= TILE_WIRE_FCO && src_id <= TILE_WIRE_FCI)) { toSameSideVer(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, src_id - TILE_WIRE_FCO); } if (dst_type == id_WIRE_TYPE_NONE && (dst_id >= TILE_WIRE_JCE0 && dst_id <= TILE_WIRE_JCE0) && src_type == id_WIRE_TYPE_NONE && (src_id >= TILE_WIRE_JCE0 && src_id <= TILE_WIRE_JCE0)) { toSameSideVer(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id, style, src_id - TILE_WIRE_JCE0); } if (dst_type == id_WIRE_TYPE_SLICE && src_type == id_WIRE_TYPE_NONE) { if (src_id >= TILE_WIRE_FCO && src_id <= TILE_WIRE_FCI && dst_id >= TILE_WIRE_FCO_SLICE && dst_id <= TILE_WIRE_FCI_SLICE) { // LUT permutation pseudo-pip int src_purpose = (src_id - TILE_WIRE_FCO) % 24; int dst_purpose = (dst_id - TILE_WIRE_FCO_SLICE) % 24; if (src_purpose >= (TILE_WIRE_D7 - TILE_WIRE_FCO) && src_purpose <= (TILE_WIRE_A6 - TILE_WIRE_FCO) && dst_purpose >= (TILE_WIRE_D7_SLICE - TILE_WIRE_FCO_SLICE) && dst_purpose <= (TILE_WIRE_A6_SLICE - TILE_WIRE_FCO_SLICE)) { lutPermPip(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id); } } } if (src_type == id_WIRE_TYPE_NONE && (dst_type.in(id_WIRE_TYPE_PLL, id_WIRE_TYPE_GSR, id_WIRE_TYPE_JTAG, id_WIRE_TYPE_OSC, id_WIRE_TYPE_SED, id_WIRE_TYPE_DTR, id_WIRE_TYPE_EXTREF, id_WIRE_TYPE_DCU, id_WIRE_TYPE_PCSCLKDIV, id_WIRE_TYPE_DDRDLL, id_WIRE_TYPE_CCLK, id_WIRE_TYPE_DQS, id_WIRE_TYPE_IOLOGIC, id_WIRE_TYPE_SIOLOGIC, id_WIRE_TYPE_EBR, id_WIRE_TYPE_MULT18, id_WIRE_TYPE_ALU54)) && (src_id >= TILE_WIRE_JCE0 && src_id <= TILE_WIRE_JQ7)) { straightLine(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id); } if (dst_type == id_WIRE_TYPE_NONE && (src_type.in(id_WIRE_TYPE_PLL, id_WIRE_TYPE_GSR, id_WIRE_TYPE_JTAG, id_WIRE_TYPE_OSC, id_WIRE_TYPE_SED, id_WIRE_TYPE_DTR, id_WIRE_TYPE_EXTREF, id_WIRE_TYPE_DCU, id_WIRE_TYPE_PCSCLKDIV, id_WIRE_TYPE_DDRDLL, id_WIRE_TYPE_CCLK, id_WIRE_TYPE_DQS, id_WIRE_TYPE_IOLOGIC, id_WIRE_TYPE_SIOLOGIC, id_WIRE_TYPE_EBR, id_WIRE_TYPE_MULT18, id_WIRE_TYPE_ALU54)) && (dst_id >= TILE_WIRE_JCE0 && dst_id <= TILE_WIRE_JQ7)) { straightLine(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id); } if (src_type == id_WIRE_TYPE_NONE && (dst_type.in(id_WIRE_TYPE_IOLOGIC, id_WIRE_TYPE_SIOLOGIC, id_WIRE_TYPE_PIO)) && (src_id >= TILE_WIRE_JDIA && src_id <= TILE_WIRE_ECLKD)) { straightLine(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id); } if (dst_type == id_WIRE_TYPE_NONE && (src_type.in(id_WIRE_TYPE_IOLOGIC, id_WIRE_TYPE_SIOLOGIC, id_WIRE_TYPE_PIO)) && (dst_id >= TILE_WIRE_JDIA && dst_id <= TILE_WIRE_ECLKD)) { straightLine(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id); } if (src_type == id_WIRE_TYPE_NONE && dst_type == id_WIRE_TYPE_NONE && (src_id >= TILE_WIRE_JDIA && src_id <= TILE_WIRE_ECLKD) && (dst_id >= TILE_WIRE_JCE0 && dst_id <= TILE_WIRE_JQ7)) { straightLine(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id); } if (dst_type == id_WIRE_TYPE_NONE && src_type == id_WIRE_TYPE_NONE && (dst_id >= TILE_WIRE_JDIA && dst_id <= TILE_WIRE_ECLKD) && (src_id >= TILE_WIRE_JCE0 && src_id <= TILE_WIRE_JQ7)) { straightLine(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id); } if (dst_type == id_WIRE_TYPE_NONE && src_type == id_WIRE_TYPE_G_HPBX && ((dst_id >= TILE_WIRE_JCE0 && dst_id <= TILE_WIRE_JQ7) || (dst_id >= TILE_WIRE_CLK0 && dst_id <= TILE_WIRE_FCI))) { straightLine(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id); } if ((dst_type.in(id_WIRE_TYPE_H01, id_WIRE_TYPE_V01)) && src_type == id_WIRE_TYPE_G_HPBX) { straightLine(g, el, x, y, w, h, src, src_type, src_id, dst, dst_type, dst_id); } } NEXTPNR_NAMESPACE_END #n1848'>1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of a Qt Solutions component.
**
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
**     the names of its contributors may be used to endorse or promote
**     products derived from this software without specific prior written
**     permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
****************************************************************************/


#include "qtpropertybrowser.h"
#include <QtCore/QSet>
#include <QtCore/QMap>
#include <QtGui/QIcon>

#if defined(Q_CC_MSVC)
#    pragma warning(disable: 4786) /* MS VS 6: truncating debug info after 255 characters */
#endif

#if QT_VERSION >= 0x040400
QT_BEGIN_NAMESPACE
#endif

class QtPropertyPrivate
{
public:
    QtPropertyPrivate(QtAbstractPropertyManager *manager) : m_enabled(true), m_selectable(true), m_modified(false), m_manager(manager) {}
    QtProperty *q_ptr;

    QSet<QtProperty *> m_parentItems;
    QList<QtProperty *> m_subItems;

    QString m_toolTip;
    QString m_statusTip;
    QString m_whatsThis;
    QString m_name;
    QString m_id;
    bool m_enabled;
    bool m_selectable;
    bool m_modified;

    QtAbstractPropertyManager * const m_manager;
};

class QtAbstractPropertyManagerPrivate
{
    QtAbstractPropertyManager *q_ptr;
    Q_DECLARE_PUBLIC(QtAbstractPropertyManager)
public:
    void propertyDestroyed(QtProperty *property);
    void propertyChanged(QtProperty *property) const;
    void propertyRemoved(QtProperty *property,
                QtProperty *parentProperty) const;
    void propertyInserted(QtProperty *property, QtProperty *parentProperty,
                QtProperty *afterProperty) const;

    QSet<QtProperty *> m_properties;
};

/*!
    \class QtProperty

    \brief The QtProperty class encapsulates an instance of a property.

    Properties are created by objects of QtAbstractPropertyManager
    subclasses; a manager can create properties of a given type, and
    is used in conjunction with the QtAbstractPropertyBrowser class. A
    property is always owned by the manager that created it, which can
    be retrieved using the propertyManager() function.

    QtProperty contains the most common property attributes, and
    provides functions for retrieving as well as setting their values:

    \table
    \header \o Getter \o Setter
    \row
    \o propertyName() \o setPropertyName()
    \row
    \o statusTip() \o setStatusTip()
    \row
    \o toolTip() \o setToolTip()
    \row
    \o whatsThis() \o setWhatsThis()
    \row
    \o isEnabled() \o setEnabled()
    \row
    \o isModified() \o setModified()
    \row
    \o valueText() \o Nop
    \row
    \o valueIcon() \o Nop
    \endtable

    It is also possible to nest properties: QtProperty provides the
    addSubProperty(), insertSubProperty() and removeSubProperty() functions to
    manipulate the set of subproperties. Use the subProperties()
    function to retrieve a property's current set of subproperties.
    Note that nested properties are not owned by the parent property,
    i.e. each subproperty is owned by the manager that created it.

    \sa QtAbstractPropertyManager, QtBrowserItem
*/

/*!
    Creates a property with the given \a manager.

    This constructor is only useful when creating a custom QtProperty
    subclass (e.g. QtVariantProperty). To create a regular QtProperty
    object, use the QtAbstractPropertyManager::addProperty()
    function instead.

    \sa QtAbstractPropertyManager::addProperty()
*/
QtProperty::QtProperty(QtAbstractPropertyManager *manager)
{
    d_ptr = new QtPropertyPrivate(manager);
    d_ptr->q_ptr = this;
}

/*!
    Destroys this property.

    Note that subproperties are detached but not destroyed, i.e. they
    can still be used in another context.

    \sa QtAbstractPropertyManager::clear()

*/
QtProperty::~QtProperty()
{
    QSetIterator<QtProperty *> itParent(d_ptr->m_parentItems);
    while (itParent.hasNext()) {
        QtProperty *property = itParent.next();
        property->d_ptr->m_manager->d_ptr->propertyRemoved(this, property);
    }

    d_ptr->m_manager->d_ptr->propertyDestroyed(this);

    QListIterator<QtProperty *> itChild(d_ptr->m_subItems);
    while (itChild.hasNext()) {
        QtProperty *property = itChild.next();
        property->d_ptr->m_parentItems.remove(this);
    }

    itParent.toFront();
    while (itParent.hasNext()) {
        QtProperty *property = itParent.next();
        property->d_ptr->m_subItems.removeAll(this);
    }
    delete d_ptr;
}

/*!
    Returns the set of subproperties.

    Note that subproperties are not owned by \e this property, but by
    the manager that created them.

    \sa insertSubProperty(), removeSubProperty()
*/
QList<QtProperty *> QtProperty::subProperties() const
{
    return d_ptr->m_subItems;
}

/*!
    Returns a pointer to the manager that owns this property.
*/
QtAbstractPropertyManager *QtProperty::propertyManager() const
{
    return d_ptr->m_manager;
}

/*!
    Returns the property's  tool tip.

    \sa setToolTip()
*/
QString QtProperty::toolTip() const
{
    return d_ptr->m_toolTip;
}

/*!
    Returns the property's status tip.

    \sa setStatusTip()
*/
QString QtProperty::statusTip() const
{
    return d_ptr->m_statusTip;
}

/*!
    Returns the property's "What's This" help text.

    \sa setWhatsThis()
*/
QString QtProperty::whatsThis() const
{
    return d_ptr->m_whatsThis;
}

/*!
    Returns the property's name.

    \sa setPropertyName()
*/
QString QtProperty::propertyName() const
{
    return d_ptr->m_name;
}

/*!
    Returns the property's id.

    \sa setPropertyId()
*/
QString QtProperty::propertyId() const
{
    return d_ptr->m_id;
}

/*!
    Returns whether the property is enabled.

    \sa setEnabled()
*/
bool QtProperty::isEnabled() const
{
    return d_ptr->m_enabled;
}

bool QtProperty::isSelectable() const
{
    return d_ptr->m_selectable;
}

/*!
    Returns whether the property is modified.

    \sa setModified()
*/
bool QtProperty::isModified() const
{
    return d_ptr->m_modified;
}

/*!
    Returns whether the property has a value.

    \sa QtAbstractPropertyManager::hasValue()
*/
bool QtProperty::hasValue() const
{
    return d_ptr->m_manager->hasValue(this);
}

/*!
    Returns an icon representing the current state of this property.

    If the given property type can not generate such an icon, this
    function returns an invalid icon.

    \sa QtAbstractPropertyManager::valueIcon()
*/
QIcon QtProperty::valueIcon() const
{
    return d_ptr->m_manager->valueIcon(this);
}

/*!
    Returns a string representing the current state of this property.

    If the given property type can not generate such a string, this
    function returns an empty string.

    \sa QtAbstractPropertyManager::valueText()
*/
QString QtProperty::valueText() const
{
    return d_ptr->m_manager->valueText(this);
}

/*!
    Returns True if this property is equal to \a otherProperty

    The list of parent or sub properties are not considered in the comparison.
*/
bool QtProperty::compare(QtProperty* otherProperty)const
{
  return (this->propertyId() == otherProperty->propertyId()
          && this->propertyName() == otherProperty->propertyName()
          && this->toolTip() == otherProperty->toolTip()
          && this->statusTip() == otherProperty->statusTip()
          && this->whatsThis() == otherProperty->whatsThis()
          && this->isEnabled() == otherProperty->isEnabled()
          && this->isModified() == otherProperty->isModified());
}

/*!
    Sets the property's tool tip to the given \a text.

    \sa toolTip()
*/
void QtProperty::setToolTip(const QString &text)
{
    if (d_ptr->m_toolTip == text)
        return;

    d_ptr->m_toolTip = text;
    propertyChanged();
}

/*!
    Sets the property's status tip to the given \a text.

    \sa statusTip()
*/
void QtProperty::setStatusTip(const QString &text)
{
    if (d_ptr->m_statusTip == text)
        return;

    d_ptr->m_statusTip = text;
    propertyChanged();
}

/*!
    Sets the property's "What's This" help text to the given \a text.

    \sa whatsThis()
*/
void QtProperty::setWhatsThis(const QString &text)
{
    if (d_ptr->m_whatsThis == text)
        return;

    d_ptr->m_whatsThis = text;
    propertyChanged();
}

/*!
    \fn void QtProperty::setPropertyName(const QString &name)

    Sets the property's  name to the given \a name.

    \sa propertyName()
*/
void QtProperty::setPropertyName(const QString &text)
{
    if (d_ptr->m_name == text)
        return;

    d_ptr->m_name = text;
    propertyChanged();
}

/*!
    \fn void QtProperty::setPropertyId(const QString &id)

    Sets the property's  id to the given \a id.

    \sa propertyId()
*/
void QtProperty::setPropertyId(const QString &text)
{
    if (d_ptr->m_id == text)
        return;

    d_ptr->m_id = text;
}

/*!
    Enables or disables the property according to the passed \a enable value.

    \sa isEnabled()
*/
void QtProperty::setEnabled(bool enable)
{
    if (d_ptr->m_enabled == enable)
        return;

    d_ptr->m_enabled = enable;
    propertyChanged();
}

void QtProperty::setSelectable(bool selectable)
{
    if (d_ptr->m_selectable == selectable)
        return;

    d_ptr->m_selectable = selectable;
    propertyChanged();
}

/*!
    Sets the property's modified state according to the passed \a modified value.

    \sa isModified()
*/
void QtProperty::setModified(bool modified)
{
    if (d_ptr->m_modified == modified)
        return;

    d_ptr->m_modified = modified;
    propertyChanged();
}

/*!
    Returns whether the property is sub property.
*/
bool QtProperty::isSubProperty()const
{
  return d_ptr->m_parentItems.count();
}

/*!
    Appends the given \a property to this property's subproperties.

    If the given \a property already is added, this function does
    nothing.

    \sa insertSubProperty(), removeSubProperty()
*/
void QtProperty::addSubProperty(QtProperty *property)
{
    QtProperty *after = 0;
    if (d_ptr->m_subItems.count() > 0)
        after = d_ptr->m_subItems.last();
    insertSubProperty(property, after);
}

/*!
    \fn void QtProperty::insertSubProperty(QtProperty *property, QtProperty *precedingProperty)

    Inserts the given \a property after the specified \a
    precedingProperty into this property's list of subproperties.  If
    \a precedingProperty is 0, the specified \a property is inserted
    at the beginning of the list.

    If the given \a property already is inserted, this function does
    nothing.

    \sa addSubProperty(), removeSubProperty()
*/
void QtProperty::insertSubProperty(QtProperty *property,
            QtProperty *afterProperty)
{
    if (!property)
        return;

    if (property == this)
        return;

    // traverse all children of item. if this item is a child of item then cannot add.
    QList<QtProperty *> pendingList = property->subProperties();
    QMap<QtProperty *, bool> visited;
    while (!pendingList.isEmpty()) {
        QtProperty *i = pendingList.first();
        if (i == this)
            return;
        pendingList.removeFirst();
        if (visited.contains(i))
            continue;
        visited[i] = true;
        pendingList += i->subProperties();
    }

    pendingList = subProperties();
    int pos = 0;
    int newPos = 0;
    QtProperty *properAfterProperty = 0;
    while (pos < pendingList.count()) {
        QtProperty *i = pendingList.at(pos);
        if (i == property)
            return; // if item is already inserted in this item then cannot add.
        if (i == afterProperty) {
            newPos = pos + 1;
            properAfterProperty = afterProperty;
        }
        pos++;
    }

    d_ptr->m_subItems.insert(newPos, property);
    property->d_ptr->m_parentItems.insert(this);

    d_ptr->m_manager->d_ptr->propertyInserted(property, this, properAfterProperty);
}

/*!
    Removes the given \a property from the list of subproperties
    without deleting it.

    \sa addSubProperty(), insertSubProperty()
*/
void QtProperty::removeSubProperty(QtProperty *property)
{
    if (!property)
        return;

    d_ptr->m_manager->d_ptr->propertyRemoved(property, this);

    QList<QtProperty *> pendingList = subProperties();
    int pos = 0;
    while (pos < pendingList.count()) {
        if (pendingList.at(pos) == property) {
            d_ptr->m_subItems.removeAt(pos);
            property->d_ptr->m_parentItems.remove(this);

            return;
        }
        pos++;
    }
}

/*!
    \internal
*/
void QtProperty::propertyChanged()
{
    d_ptr->m_manager->d_ptr->propertyChanged(this);
}

////////////////////////////////

void QtAbstractPropertyManagerPrivate::propertyDestroyed(QtProperty *property)
{
    if (m_properties.contains(property)) {
        emit q_ptr->propertyDestroyed(property);
        q_ptr->uninitializeProperty(property);
        m_properties.remove(property);
    }
}

void QtAbstractPropertyManagerPrivate::propertyChanged(QtProperty *property) const
{
    emit q_ptr->propertyChanged(property);
}

void QtAbstractPropertyManagerPrivate::propertyRemoved(QtProperty *property,
            QtProperty *parentProperty) const
{
    emit q_ptr->propertyRemoved(property, parentProperty);
}

void QtAbstractPropertyManagerPrivate::propertyInserted(QtProperty *property,
            QtProperty *parentProperty, QtProperty *afterProperty) const
{
    emit q_ptr->propertyInserted(property, parentProperty, afterProperty);
}

/*!
    \class QtAbstractPropertyManager

    \brief The QtAbstractPropertyManager provides an interface for
    property managers.

    A manager can create and manage properties of a given type, and is
    used in conjunction with the QtAbstractPropertyBrowser class.

    When using a property browser widget, the properties are created
    and managed by implementations of the QtAbstractPropertyManager
    class. To ensure that the properties' values will be displayed
    using suitable editing widgets, the managers are associated with
    objects of QtAbstractEditorFactory subclasses. The property browser
    will use these associations to determine which factories it should
    use to create the preferred editing widgets.

    The QtAbstractPropertyManager class provides common functionality
    like creating a property using the addProperty() function, and
    retrieving the properties created by the manager using the
    properties() function. The class also provides signals that are
    emitted when the manager's properties change: propertyInserted(),
    propertyRemoved(), propertyChanged() and propertyDestroyed().

    QtAbstractPropertyManager subclasses are supposed to provide their
    own type specific API. Note that several ready-made
    implementations are available:

    \list
    \o QtBoolPropertyManager
    \o QtColorPropertyManager
    \o QtDatePropertyManager
    \o QtDateTimePropertyManager
    \o QtDoublePropertyManager
    \o QtEnumPropertyManager
    \o QtFlagPropertyManager
    \o QtFontPropertyManager
    \o QtGroupPropertyManager
    \o QtIntPropertyManager
    \o QtPointPropertyManager
    \o QtRectPropertyManager
    \o QtSizePropertyManager
    \o QtSizePolicyPropertyManager
    \o QtStringPropertyManager
    \o QtTimePropertyManager
    \o QtVariantPropertyManager
    \endlist

    \sa QtAbstractEditorFactoryBase, QtAbstractPropertyBrowser, QtProperty
*/

/*!
    \fn void QtAbstractPropertyManager::propertyInserted(QtProperty *newProperty,
                QtProperty *parentProperty, QtProperty *precedingProperty)

    This signal is emitted when a new subproperty is inserted into an
    existing property, passing pointers to the \a newProperty, \a
    parentProperty and \a precedingProperty as parameters.

    If \a precedingProperty is 0, the \a newProperty was inserted at
    the beginning of the \a parentProperty's subproperties list.

    Note that signal is emitted only if the \a parentProperty is created
    by this manager.

    \sa QtAbstractPropertyBrowser::itemInserted()
*/

/*!
    \fn void QtAbstractPropertyManager::propertyChanged(QtProperty *property)

    This signal is emitted whenever a property's data changes, passing
    a pointer to the \a property as parameter.

    Note that signal is only emitted for properties that are created by
    this manager.

    \sa QtAbstractPropertyBrowser::itemChanged()
*/

/*!
    \fn void QtAbstractPropertyManager::propertyRemoved(QtProperty *property, QtProperty *parent)

    This signal is emitted when a subproperty is removed, passing
    pointers to the removed \a property and the \a parent property as
    parameters.

    Note that signal is emitted only when the \a parent property is
    created by this manager.

    \sa QtAbstractPropertyBrowser::itemRemoved()
*/

/*!
    \fn void QtAbstractPropertyManager::propertyDestroyed(QtProperty *property)

    This signal is emitted when the specified \a property is about to
    be destroyed.

    Note that signal is only emitted for properties that are created
    by this manager.

    \sa clear(), uninitializeProperty()
*/

/*!
    \fn void QtAbstractPropertyBrowser::currentItemChanged(QtBrowserItem *current)

    This signal is emitted when the current item changes. The current item is specified by \a current.

    \sa QtAbstractPropertyBrowser::setCurrentItem()
*/

/*!
    Creates an abstract property manager with the given \a parent.
*/
QtAbstractPropertyManager::QtAbstractPropertyManager(QObject *parent)
    : QObject(parent)
{
    d_ptr = new QtAbstractPropertyManagerPrivate;
    d_ptr->q_ptr = this;

}

/*!
    Destroys the manager. All properties created by the manager are
    destroyed.
*/
QtAbstractPropertyManager::~QtAbstractPropertyManager()
{
    clear();
    delete d_ptr;
}

/*!
    Destroys all the properties that this manager has created.

    \sa propertyDestroyed(), uninitializeProperty()
*/
void QtAbstractPropertyManager::clear() const
{
    while (!properties().isEmpty()) {
        QSetIterator<QtProperty *> itProperty(properties());
        QtProperty *prop = itProperty.next();
        delete prop;
    }
}

/*!
    Returns the set of properties created by this manager.

    \sa addProperty()
*/
QSet<QtProperty *> QtAbstractPropertyManager::properties() const
{
    return d_ptr->m_properties;
}

/*!
    Returns whether the given \a property has a value.

    The default implementation of this function returns true.

    \sa QtProperty::hasValue()
*/
bool QtAbstractPropertyManager::hasValue(const QtProperty *property) const
{
    Q_UNUSED(property)
    return true;
}

/*!
    Returns an icon representing the current state of the given \a
    property.

    The default implementation of this function returns an invalid
    icon.

    \sa QtProperty::valueIcon()
*/
QIcon QtAbstractPropertyManager::valueIcon(const QtProperty *property) const
{
    Q_UNUSED(property)
    return QIcon();
}

/*!
    Returns a string representing the current state of the given \a
    property.

    The default implementation of this function returns an empty
    string.

    \sa QtProperty::valueText()
*/
QString QtAbstractPropertyManager::valueText(const QtProperty *property) const
{
    Q_UNUSED(property)
    return QString();
}

/*!
    Creates a property with the given \a name which then is owned by this manager.

    Internally, this function calls the createProperty() and
    initializeProperty() functions.

    \sa initializeProperty(), properties()
*/
QtProperty *QtAbstractPropertyManager::addProperty(const QString &name)
{
    QtProperty *property = createProperty();
    if (property) {
        property->setPropertyName(name);
        d_ptr->m_properties.insert(property);
        initializeProperty(property);
    }
    return property;
}

/*!
    Return the QtProperty object matching \a id or Null if any.

    \sa addProperty(), setPropertyId(const QString&), properties()
*/
QtProperty * QtAbstractPropertyManager::qtProperty(const QString &id)const
{
  foreach(QtProperty* prop, d_ptr->m_properties)
    {
    if (prop->propertyId() == id)
      {
      return prop;
      }
    }
  return 0;
}

/*!
    Creates a property.

    The base implementation produce QtProperty instances; Reimplement
    this function to make this manager produce objects of a QtProperty
    subclass.

    \sa addProperty(), initializeProperty()
*/
QtProperty *QtAbstractPropertyManager::createProperty()
{
    return new QtProperty(this);
}

/*!
    \fn void QtAbstractPropertyManager::initializeProperty(QtProperty *property) = 0

    This function is called whenever a new valid property pointer has
    been created, passing the pointer as parameter.

    The purpose is to let the manager know that the \a property has
    been created so that it can provide additional attributes for the
    new property, e.g. QtIntPropertyManager adds \l
    {QtIntPropertyManager::value()}{value}, \l
    {QtIntPropertyManager::minimum()}{minimum} and \l
    {QtIntPropertyManager::maximum()}{maximum} attributes. Since each manager
    subclass adds type specific attributes, this function is pure
    virtual and must be reimplemented when deriving from the
    QtAbstractPropertyManager class.

    \sa addProperty(), createProperty()
*/

/*!
    This function is called just before the specified \a property is destroyed.

    The purpose is to let the property manager know that the \a
    property is being destroyed so that it can remove the property's
    additional attributes.

    \sa clear(),  propertyDestroyed()
*/
void QtAbstractPropertyManager::uninitializeProperty(QtProperty *property)
{
    Q_UNUSED(property)
}

////////////////////////////////////

/*!
    \class QtAbstractEditorFactoryBase

    \brief The QtAbstractEditorFactoryBase provides an interface for
    editor factories.

    An editor factory is a class that is able to create an editing
    widget of a specified type (e.g. line edits or comboboxes) for a
    given QtProperty object, and it is used in conjunction with the
    QtAbstractPropertyManager and QtAbstractPropertyBrowser classes.

    When using a property browser widget, the properties are created
    and managed by implementations of the QtAbstractPropertyManager
    class. To ensure that the properties' values will be displayed
    using suitable editing widgets, the managers are associated with
    objects of QtAbstractEditorFactory subclasses. The property browser
    will use these associations to determine which factories it should
    use to create the preferred editing widgets.

    Typically, an editor factory is created by subclassing the
    QtAbstractEditorFactory template class which inherits
    QtAbstractEditorFactoryBase. But note that several ready-made
    implementations are available:

    \list
    \o QtCheckBoxFactory
    \o QtDateEditFactory
    \o QtDateTimeEditFactory
    \o QtDoubleSpinBoxFactory
    \o QtEnumEditorFactory
    \o QtLineEditFactory
    \o QtScrollBarFactory
    \o QtSliderFactory
    \o QtSpinBoxFactory
    \o QtTimeEditFactory
    \o QtVariantEditorFactory
    \endlist

    \sa QtAbstractPropertyManager, QtAbstractPropertyBrowser
*/

/*!
    \fn virtual QWidget *QtAbstractEditorFactoryBase::createEditor(QtProperty *property,
        QWidget *parent) = 0

    Creates an editing widget (with the given \a parent) for the given
    \a property.

    This function is reimplemented in QtAbstractEditorFactory template class
    which also provides a pure virtual convenience overload of this
    function enabling access to the property's manager.

    \sa  QtAbstractEditorFactory::createEditor()
*/

/*!
    \fn QtAbstractEditorFactoryBase::QtAbstractEditorFactoryBase(QObject *parent = 0)

    Creates an abstract editor factory with the given \a parent.
*/

/*!
    \fn virtual void QtAbstractEditorFactoryBase::breakConnection(QtAbstractPropertyManager *manager) = 0

    \internal

    Detaches property manager from factory.
    This method is reimplemented in QtAbstractEditorFactory template subclass.
    You don't need to reimplement it in your subclasses. Instead implement more convenient
    QtAbstractEditorFactory::disconnectPropertyManager() which gives you access to particular manager subclass.
*/

/*!
    \fn virtual void QtAbstractEditorFactoryBase::managerDestroyed(QObject *manager) = 0

    \internal

    This method is called when property manager is being destroyed.
    Basically it notifies factory not to produce editors for properties owned by \a manager.
    You don't need to reimplement it in your subclass. This method is implemented in
    QtAbstractEditorFactory template subclass.
*/

/*!
    \class QtAbstractEditorFactory

    \brief The QtAbstractEditorFactory is the base template class for editor
    factories.

    An editor factory is a class that is able to create an editing
    widget of a specified type (e.g. line edits or comboboxes) for a
    given QtProperty object, and it is used in conjunction with the
    QtAbstractPropertyManager and QtAbstractPropertyBrowser classes.

    Note that the QtAbstractEditorFactory functions are using the
    PropertyManager template argument class which can be any
    QtAbstractPropertyManager subclass. For example:

    \code
        QtSpinBoxFactory *factory;
        QSet<QtIntPropertyManager *> managers = factory->propertyManagers();
    \endcode

    Note that QtSpinBoxFactory by definition creates editing widgets
    \e only for properties created by QtIntPropertyManager.

    When using a property browser widget, the properties are created
    and managed by implementations of the QtAbstractPropertyManager
    class. To ensure that the properties' values will be displayed
    using suitable editing widgets, the managers are associated with
    objects of QtAbstractEditorFactory subclasses. The property browser will
    use these associations to determine which factories it should use
    to create the preferred editing widgets.

    A QtAbstractEditorFactory object is capable of producing editors for
    several property managers at the same time. To create an
    association between this factory and a given manager, use the
    addPropertyManager() function. Use the removePropertyManager() function to make
    this factory stop producing editors for a given property
    manager. Use the propertyManagers() function to retrieve the set of
    managers currently associated with this factory.

    Several ready-made implementations of the QtAbstractEditorFactory class
    are available:

    \list
    \o QtCheckBoxFactory
    \o QtDateEditFactory
    \o QtDateTimeEditFactory
    \o QtDoubleSpinBoxFactory
    \o QtEnumEditorFactory
    \o QtLineEditFactory
    \o QtScrollBarFactory
    \o QtSliderFactory
    \o QtSpinBoxFactory
    \o QtTimeEditFactory
    \o QtVariantEditorFactory
    \endlist

    When deriving from the QtAbstractEditorFactory class, several pure virtual
    functions must be implemented: the connectPropertyManager() function is
    used by the factory to connect to the given manager's signals, the
    createEditor() function is supposed to create an editor for the
    given property controlled by the given manager, and finally the
    disconnectPropertyManager() function is used by the factory to disconnect
    from the specified manager's signals.

    \sa QtAbstractEditorFactoryBase, QtAbstractPropertyManager
*/

/*!
    \fn QtAbstractEditorFactory::QtAbstractEditorFactory(QObject *parent = 0)

    Creates an editor factory with the given \a parent.

    \sa addPropertyManager()
*/

/*!
    \fn QWidget *QtAbstractEditorFactory::createEditor(QtProperty *property, QWidget *parent)

    Creates an editing widget (with the given \a parent) for the given
    \a property.
*/

/*!
    \fn void QtAbstractEditorFactory::addPropertyManager(PropertyManager *manager)

    Adds the given \a manager to this factory's set of managers,
    making this factory produce editing widgets for properties created
    by the given manager.

    The PropertyManager type is a template argument class, and represents the chosen
    QtAbstractPropertyManager subclass.

    \sa propertyManagers(), removePropertyManager()
*/

/*!
    \fn void QtAbstractEditorFactory::removePropertyManager(PropertyManager *manager)

    Removes the given \a manager from this factory's set of
    managers. The PropertyManager type is a template argument class, and may be
    any QtAbstractPropertyManager subclass.

    \sa propertyManagers(), addPropertyManager()
*/

/*!
    \fn virtual void QtAbstractEditorFactory::connectPropertyManager(PropertyManager *manager) = 0

    Connects this factory to the given \a manager's signals.  The
    PropertyManager type is a template argument class, and represents
    the chosen QtAbstractPropertyManager subclass.

    This function is used internally by the addPropertyManager() function, and
    makes it possible to update an editing widget when the associated
    property's data changes. This is typically done in custom slots
    responding to the signals emitted by the property's manager,
    e.g. QtIntPropertyManager::valueChanged() and
    QtIntPropertyManager::rangeChanged().

    \sa propertyManagers(), disconnectPropertyManager()
*/

/*!
    \fn virtual QWidget *QtAbstractEditorFactory::createEditor(PropertyManager *manager, QtProperty *property,
                QWidget *parent) = 0

    Creates an editing widget with the given \a parent for the
    specified \a property created by the given \a manager. The
    PropertyManager type is a template argument class, and represents
    the chosen QtAbstractPropertyManager subclass.

    This function must be implemented in derived classes: It is
    recommended to store a pointer to the widget and map it to the
    given \a property, since the widget must be updated whenever the
    associated property's data changes. This is typically done in
    custom slots responding to the signals emitted by the property's
    manager, e.g. QtIntPropertyManager::valueChanged() and
    QtIntPropertyManager::rangeChanged().

    \sa connectPropertyManager()
*/

/*!
    \fn virtual void QtAbstractEditorFactory::disconnectPropertyManager(PropertyManager *manager) = 0

    Disconnects this factory from the given \a manager's signals. The
    PropertyManager type is a template argument class, and represents
    the chosen QtAbstractPropertyManager subclass.

    This function is used internally by the removePropertyManager() function.

    \sa propertyManagers(), connectPropertyManager()
*/

/*!
    \fn QSet<PropertyManager *> QtAbstractEditorFactory::propertyManagers() const

    Returns the factory's set of associated managers.  The
    PropertyManager type is a template argument class, and represents
    the chosen QtAbstractPropertyManager subclass.

    \sa addPropertyManager(), removePropertyManager()
*/

/*!
    \fn PropertyManager *QtAbstractEditorFactory::propertyManager(QtProperty *property) const

    Returns the property manager for the given \a property, or 0 if
    the given \a property doesn't belong to any of this factory's
    registered managers.

    The PropertyManager type is a template argument class, and represents the chosen
    QtAbstractPropertyManager subclass.

    \sa propertyManagers()
*/

/*!
    \fn virtual void QtAbstractEditorFactory::managerDestroyed(QObject *manager)

    \internal
    \reimp
*/

////////////////////////////////////
class QtBrowserItemPrivate
{
public:
    QtBrowserItemPrivate(QtAbstractPropertyBrowser *browser, QtProperty *property, QtBrowserItem *parent)
        : m_browser(browser), m_property(property), m_parent(parent), q_ptr(0) {}

    void addChild(QtBrowserItem *index, QtBrowserItem *after);
    void removeChild(QtBrowserItem *index);

    QtAbstractPropertyBrowser * const m_browser;
    QtProperty *m_property;
    QtBrowserItem *m_parent;

    QtBrowserItem *q_ptr;

    QList<QtBrowserItem *> m_children;

};

void QtBrowserItemPrivate::addChild(QtBrowserItem *index, QtBrowserItem *after)
{
    if (m_children.contains(index))
        return;
    int idx = m_children.indexOf(after) + 1; // we insert after returned idx, if it was -1 then we set idx to 0;
    m_children.insert(idx, index);
}

void QtBrowserItemPrivate::removeChild(QtBrowserItem *index)
{
    m_children.removeAll(index);
}


/*!
    \class QtBrowserItem

    \brief The QtBrowserItem class represents a property in
    a property browser instance.

    Browser items are created whenever a QtProperty is inserted to the
    property browser. A QtBrowserItem uniquely identifies a
    browser's item. Thus, if the same QtProperty is inserted multiple
    times, each occurrence gets its own unique QtBrowserItem. The
    items are owned by QtAbstractPropertyBrowser and automatically
    deleted when they are removed from the browser.

    You can traverse a browser's properties by calling parent() and
    children(). The property and the browser associated with an item
    are available as property() and browser().

    \sa QtAbstractPropertyBrowser, QtProperty
*/

/*!
    Returns the property which is accosiated with this item. Note that
    several items can be associated with the same property instance in
    the same property browser.

    \sa QtAbstractPropertyBrowser::items()
*/

QtProperty *QtBrowserItem::property() const
{
    return d_ptr->m_property;
}

/*!
    Returns the parent item of \e this item. Returns 0 if \e this item
    is associated with top-level property in item's property browser.

    \sa children()
*/

QtBrowserItem *QtBrowserItem::parent() const
{
    return d_ptr->m_parent;
}

/*!
    Returns the children items of \e this item. The properties
    reproduced from children items are always the same as
    reproduced from associated property' children, for example:

    \code
        QtBrowserItem *item;
        QList<QtBrowserItem *> childrenItems = item->children();

        QList<QtProperty *> childrenProperties = item->property()->subProperties();
    \endcode

    The \e childrenItems list represents the same list as \e childrenProperties.
*/

QList<QtBrowserItem *> QtBrowserItem::children() const
{
    return d_ptr->m_children;
}

/*!
    Returns the property browser which owns \e this item.
*/

QtAbstractPropertyBrowser *QtBrowserItem::browser() const
{
    return d_ptr->m_browser;
}

QtBrowserItem::QtBrowserItem(QtAbstractPropertyBrowser *browser, QtProperty *property, QtBrowserItem *parent)
{
    d_ptr = new QtBrowserItemPrivate(browser, property, parent);
    d_ptr->q_ptr = this;
}

QtBrowserItem::~QtBrowserItem()
{
    delete d_ptr;
}


////////////////////////////////////

typedef QMap<QtAbstractPropertyBrowser *, QMap<QtAbstractPropertyManager *,
                            QtAbstractEditorFactoryBase *> > Map1;
typedef QMap<QtAbstractPropertyManager *, QMap<QtAbstractEditorFactoryBase *,
                            QList<QtAbstractPropertyBrowser *> > > Map2;
Q_GLOBAL_STATIC(Map1, m_viewToManagerToFactory)
Q_GLOBAL_STATIC(Map2, m_managerToFactoryToViews)

class QtAbstractPropertyBrowserPrivate
{
    QtAbstractPropertyBrowser *q_ptr;
    Q_DECLARE_PUBLIC(QtAbstractPropertyBrowser)
public:
    QtAbstractPropertyBrowserPrivate();

    void insertSubTree(QtProperty *property,
            QtProperty *parentProperty);
    void removeSubTree(QtProperty *property,
            QtProperty *parentProperty);
    void createBrowserIndexes(QtProperty *property, QtProperty *parentProperty, QtProperty *afterProperty);
    void removeBrowserIndexes(QtProperty *property, QtProperty *parentProperty);
    QtBrowserItem *createBrowserIndex(QtProperty *property, QtBrowserItem *parentIndex, QtBrowserItem *afterIndex);
    void removeBrowserIndex(QtBrowserItem *index);
    void clearIndex(QtBrowserItem *index);

    void slotPropertyInserted(QtProperty *property,
            QtProperty *parentProperty, QtProperty *afterProperty);
    void slotPropertyRemoved(QtProperty *property, QtProperty *parentProperty);
    void slotPropertyDestroyed(QtProperty *property);
    void slotPropertyDataChanged(QtProperty *property);

    QList<QtProperty *> m_subItems;
    QMap<QtAbstractPropertyManager *, QList<QtProperty *> > m_managerToProperties;
    QMap<QtProperty *, QList<QtProperty *> > m_propertyToParents;

    QMap<QtProperty *, QtBrowserItem *> m_topLevelPropertyToIndex;
    QList<QtBrowserItem *> m_topLevelIndexes;
    QMap<QtProperty *, QList<QtBrowserItem *> > m_propertyToIndexes;

    QtBrowserItem *m_currentItem;
};

QtAbstractPropertyBrowserPrivate::QtAbstractPropertyBrowserPrivate() :
   m_currentItem(0)
{
}

void QtAbstractPropertyBrowserPrivate::insertSubTree(QtProperty *property,
            QtProperty *parentProperty)
{
    if (m_propertyToParents.contains(property)) {
        // property was already inserted, so its manager is connected
        // and all its children are inserted and theirs managers are connected
        // we just register new parent (parent has to be new).
        m_propertyToParents[property].append(parentProperty);
        // don't need to update m_managerToProperties map since
        // m_managerToProperties[manager] already contains property.
        return;
    }
    QtAbstractPropertyManager *manager = property->propertyManager();
    if (m_managerToProperties[manager].isEmpty()) {
        // connect manager's signals
        q_ptr->connect(manager, SIGNAL(propertyInserted(QtProperty *,
                            QtProperty *, QtProperty *)),
                q_ptr, SLOT(slotPropertyInserted(QtProperty *,
                            QtProperty *, QtProperty *)));
        q_ptr->connect(manager, SIGNAL(propertyRemoved(QtProperty *,
                            QtProperty *)),
                q_ptr, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *)));
        q_ptr->connect(manager, SIGNAL(propertyDestroyed(QtProperty *)),
                q_ptr, SLOT(slotPropertyDestroyed(QtProperty *)));
        q_ptr->connect(manager, SIGNAL(propertyChanged(QtProperty *)),
                q_ptr, SLOT(slotPropertyDataChanged(QtProperty *)));
    }
    m_managerToProperties[manager].append(property);
    m_propertyToParents[property].append(parentProperty);

    QList<QtProperty *> subList = property->subProperties();
    QListIterator<QtProperty *> itSub(subList);
    while (itSub.hasNext()) {
        QtProperty *subProperty = itSub.next();
        insertSubTree(subProperty, property);
    }
}

void QtAbstractPropertyBrowserPrivate::removeSubTree(QtProperty *property,
            QtProperty *parentProperty)
{
    if (!m_propertyToParents.contains(property)) {
        // ASSERT
        return;
    }

    m_propertyToParents[property].removeAll(parentProperty);
    if (!m_propertyToParents[property].isEmpty())
        return;

    m_propertyToParents.remove(property);
    QtAbstractPropertyManager *manager = property->propertyManager();
    m_managerToProperties[manager].removeAll(property);
    if (m_managerToProperties[manager].isEmpty()) {
        // disconnect manager's signals
        q_ptr->disconnect(manager, SIGNAL(propertyInserted(QtProperty *,
                            QtProperty *, QtProperty *)),
                q_ptr, SLOT(slotPropertyInserted(QtProperty *,
                            QtProperty *, QtProperty *)));
        q_ptr->disconnect(manager, SIGNAL(propertyRemoved(QtProperty *,
                            QtProperty *)),
                q_ptr, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *)));
        q_ptr->disconnect(manager, SIGNAL(propertyDestroyed(QtProperty *)),
                q_ptr, SLOT(slotPropertyDestroyed(QtProperty *)));
        q_ptr->disconnect(manager, SIGNAL(propertyChanged(QtProperty *)),
                q_ptr, SLOT(slotPropertyDataChanged(QtProperty *)));

        m_managerToProperties.remove(manager);
    }

    QList<QtProperty *> subList = property->subProperties();
    QListIterator<QtProperty *> itSub(subList);
    while (itSub.hasNext()) {
        QtProperty *subProperty = itSub.next();
        removeSubTree(subProperty, property);
    }
}

void QtAbstractPropertyBrowserPrivate::createBrowserIndexes(QtProperty *property, QtProperty *parentProperty, QtProperty *afterProperty)
{
    QMap<QtBrowserItem *, QtBrowserItem *> parentToAfter;
    if (afterProperty) {
        QMap<QtProperty *, QList<QtBrowserItem *> >::ConstIterator it =
            m_propertyToIndexes.find(afterProperty);
        if (it == m_propertyToIndexes.constEnd())
            return;

        QList<QtBrowserItem *> indexes = it.value();
        QListIterator<QtBrowserItem *> itIndex(indexes);
        while (itIndex.hasNext()) {
            QtBrowserItem *idx = itIndex.next();
            QtBrowserItem *parentIdx = idx->parent();
            if ((parentProperty && parentIdx && parentIdx->property() == parentProperty) || (!parentProperty && !parentIdx))
                parentToAfter[idx->parent()] = idx;
        }
    } else if (parentProperty) {
        QMap<QtProperty *, QList<QtBrowserItem *> >::ConstIterator it =
                m_propertyToIndexes.find(parentProperty);
        if (it == m_propertyToIndexes.constEnd())
            return;

        QList<QtBrowserItem *> indexes = it.value();
        QListIterator<QtBrowserItem *> itIndex(indexes);
        while (itIndex.hasNext()) {
            QtBrowserItem *idx = itIndex.next();
            parentToAfter[idx] = 0;
        }
    } else {
        parentToAfter[0] = 0;
    }

    const QMap<QtBrowserItem *, QtBrowserItem *>::ConstIterator pcend = parentToAfter.constEnd();
    for (QMap<QtBrowserItem *, QtBrowserItem *>::ConstIterator it = parentToAfter.constBegin(); it != pcend; ++it)
        createBrowserIndex(property, it.key(), it.value());
}

QtBrowserItem *QtAbstractPropertyBrowserPrivate::createBrowserIndex(QtProperty *property,
        QtBrowserItem *parentIndex, QtBrowserItem *afterIndex)
{
    QtBrowserItem *newIndex = new QtBrowserItem(q_ptr, property, parentIndex);
    if (parentIndex) {
        parentIndex->d_ptr->addChild(newIndex, afterIndex);
    } else {
        m_topLevelPropertyToIndex[property] = newIndex;
        m_topLevelIndexes.insert(m_topLevelIndexes.indexOf(afterIndex) + 1, newIndex);
    }
    m_propertyToIndexes[property].append(newIndex);

    q_ptr->itemInserted(newIndex, afterIndex);

    QList<QtProperty *> subItems = property->subProperties();
    QListIterator<QtProperty *> itChild(subItems);
    QtBrowserItem *afterChild = 0;
    while (itChild.hasNext()) {
        QtProperty *child = itChild.next();
        afterChild = createBrowserIndex(child, newIndex, afterChild);
    }
    return newIndex;
}

void QtAbstractPropertyBrowserPrivate::removeBrowserIndexes(QtProperty *property, QtProperty *parentProperty)
{
    QList<QtBrowserItem *> toRemove;
    QMap<QtProperty *, QList<QtBrowserItem *> >::ConstIterator it =
        m_propertyToIndexes.find(property);
    if (it == m_propertyToIndexes.constEnd())
        return;

    QList<QtBrowserItem *> indexes = it.value();
    QListIterator<QtBrowserItem *> itIndex(indexes);
    while (itIndex.hasNext()) {
        QtBrowserItem *idx = itIndex.next();
        QtBrowserItem *parentIdx = idx->parent();
        if ((parentProperty && parentIdx && parentIdx->property() == parentProperty) || (!parentProperty && !parentIdx))
            toRemove.append(idx);
    }

    QListIterator<QtBrowserItem *> itRemove(toRemove);
    while (itRemove.hasNext()) {
        QtBrowserItem *index = itRemove.next();
        removeBrowserIndex(index);
    }
}

void QtAbstractPropertyBrowserPrivate::removeBrowserIndex(QtBrowserItem *index)
{
    QList<QtBrowserItem *> children = index->children();
    for (int i = children.count(); i > 0; i--) {
        removeBrowserIndex(children.at(i - 1));
    }

    q_ptr->itemRemoved(index);

    if (index->parent()) {
        index->parent()->d_ptr->removeChild(index);
    } else {
        m_topLevelPropertyToIndex.remove(index->property());
        m_topLevelIndexes.removeAll(index);
    }

    QtProperty *property = index->property();

    m_propertyToIndexes[property].removeAll(index);
    if (m_propertyToIndexes[property].isEmpty())
        m_propertyToIndexes.remove(property);

    delete index;
}

void QtAbstractPropertyBrowserPrivate::clearIndex(QtBrowserItem *index)
{
    QList<QtBrowserItem *> children = index->children();
    QListIterator<QtBrowserItem *> itChild(children);
    while (itChild.hasNext()) {
        clearIndex(itChild.next());
    }
    delete index;
}

void QtAbstractPropertyBrowserPrivate::slotPropertyInserted(QtProperty *property,
        QtProperty *parentProperty, QtProperty *afterProperty)
{
    if (!m_propertyToParents.contains(parentProperty))
        return;
    createBrowserIndexes(property, parentProperty, afterProperty);
    insertSubTree(property, parentProperty);
    //q_ptr->propertyInserted(property, parentProperty, afterProperty);
}

void QtAbstractPropertyBrowserPrivate::slotPropertyRemoved(QtProperty *property,
        QtProperty *parentProperty)
{
    if (!m_propertyToParents.contains(parentProperty))
        return;
    removeSubTree(property, parentProperty); // this line should be probably moved down after propertyRemoved call
    //q_ptr->propertyRemoved(property, parentProperty);
    removeBrowserIndexes(property, parentProperty);
}

void QtAbstractPropertyBrowserPrivate::slotPropertyDestroyed(QtProperty *property)
{
    if (!m_subItems.contains(property))
        return;
    q_ptr->removeProperty(property);
}

void QtAbstractPropertyBrowserPrivate::slotPropertyDataChanged(QtProperty *property)
{
    if (!m_propertyToParents.contains(property))
        return;

    QMap<QtProperty *, QList<QtBrowserItem *> >::ConstIterator it =
            m_propertyToIndexes.find(property);
    if (it == m_propertyToIndexes.constEnd())
        return;

    QList<QtBrowserItem *> indexes = it.value();
    QListIterator<QtBrowserItem *> itIndex(indexes);
    while (itIndex.hasNext()) {
        QtBrowserItem *idx = itIndex.next();
        q_ptr->itemChanged(idx);
    }
    //q_ptr->propertyChanged(property);
}

/*!
    \class QtAbstractPropertyBrowser

    \brief QtAbstractPropertyBrowser provides a base class for
    implementing property browsers.

    A property browser is a widget that enables the user to edit a
    given set of properties.  Each property is represented by a label
    specifying the property's name, and an editing widget (e.g. a line
    edit or a combobox) holding its value. A property can have zero or
    more subproperties.

    \image qtpropertybrowser.png

    The top level properties can be retrieved using the
    properties() function. To traverse each property's
    subproperties, use the QtProperty::subProperties() function. In
    addition, the set of top level properties can be manipulated using
    the addProperty(), insertProperty() and removeProperty()
    functions. Note that the QtProperty class provides a corresponding
    set of functions making it possible to manipulate the set of
    subproperties as well.

    To remove all the properties from the property browser widget, use
    the clear() function. This function will clear the editor, but it
    will not delete the properties since they can still be used in
    other editors.

    The properties themselves are created and managed by
    implementations of the QtAbstractPropertyManager class. A manager
    can handle (i.e. create and manage) properties of a given type. In
    the property browser the managers are associated with
    implementations of the QtAbstractEditorFactory: A factory is a
    class able to create an editing widget of a specified type.

    When using a property browser widget, managers must be created for
    each of the required property types before the properties
    themselves can be created. To ensure that the properties' values
    will be displayed using suitable editing widgets, the managers
    must be associated with objects of the preferred factory
    implementations using the setFactoryForManager() function. The
    property browser will use these associations to determine which
    factory it should use to create the preferred editing widget.

    Note that a factory can be associated with many managers, but a
    manager can only be associated with one single factory within the
    context of a single property browser.  The associations between
    managers and factories can at any time be removed using the
    unsetFactoryForManager() function.

    Whenever the property data changes or a property is inserted or
    removed, the itemChanged(), itemInserted() or
    itemRemoved() functions are called, respectively. These
    functions must be reimplemented in derived classes in order to
    update the property browser widget. Be aware that some property
    instances can appear several times in an abstract tree
    structure. For example:

    \table 100%
    \row
    \o
    \code
        QtProperty *property1, *property2, *property3;

        property2->addSubProperty(property1);
        property3->addSubProperty(property2);

        QtAbstractPropertyBrowser *editor;

        editor->addProperty(property1);
        editor->addProperty(property2);
        editor->addProperty(property3);
    \endcode
    \o  \image qtpropertybrowser-duplicate.png
    \endtable

    The addProperty() function returns a QtBrowserItem that uniquely
    identifies the created item.

    To make a property editable in the property browser, the
    createEditor() function must be called to provide the
    property with a suitable editing widget.

    Note that there are two ready-made property browser
    implementations:

    \list
        \o QtGroupBoxPropertyBrowser
        \o QtTreePropertyBrowser
    \endlist

    \sa QtAbstractPropertyManager, QtAbstractEditorFactoryBase
*/

/*!
    \fn void QtAbstractPropertyBrowser::setFactoryForManager(PropertyManager *manager,
                    QtAbstractEditorFactory<PropertyManager> *factory)

    Connects the given \a manager to the given \a factory, ensuring
    that properties of the \a manager's type will be displayed with an
    editing widget suitable for their value.

    For example:

    \code
        QtIntPropertyManager *intManager;
        QtDoublePropertyManager *doubleManager;

        QtProperty *myInteger = intManager->addProperty();
        QtProperty *myDouble = doubleManager->addProperty();

        QtSpinBoxFactory  *spinBoxFactory;
        QtDoubleSpinBoxFactory *doubleSpinBoxFactory;

        QtAbstractPropertyBrowser *editor;
        editor->setFactoryForManager(intManager, spinBoxFactory);
        editor->setFactoryForManager(doubleManager, doubleSpinBoxFactory);

        editor->addProperty(myInteger);
        editor->addProperty(myDouble);
    \endcode

    In this example the \c myInteger property's value is displayed
    with a QSpinBox widget, while the \c myDouble property's value is
    displayed with a QDoubleSpinBox widget.

    Note that a factory can be associated with many managers, but a
    manager can only be associated with one single factory.  If the
    given \a manager already is associated with another factory, the
    old association is broken before the new one established.

    This function ensures that the given \a manager and the given \a
    factory are compatible, and it automatically calls the
    QtAbstractEditorFactory::addPropertyManager() function if necessary.

    \sa unsetFactoryForManager()
*/

/*!
    \fn virtual void QtAbstractPropertyBrowser::itemInserted(QtBrowserItem *insertedItem,
        QtBrowserItem *precedingItem) = 0

    This function is called to update the widget whenever a property
    is inserted or added to the property browser, passing pointers to
    the \a insertedItem of property and the specified
    \a precedingItem as parameters.

    If \a precedingItem is 0, the \a insertedItem was put at
    the beginning of its parent item's list of subproperties. If
    the parent of \a insertedItem is 0, the \a insertedItem was added as a top
    level property of \e this property browser.

    This function must be reimplemented in derived classes. Note that
    if the \a insertedItem's property has subproperties, this
    method will be called for those properties as soon as the current call is finished.

    \sa insertProperty(), addProperty()
*/

/*!
    \fn virtual void QtAbstractPropertyBrowser::itemRemoved(QtBrowserItem *item) = 0

    This function is called to update the widget whenever a property
    is removed from the property browser, passing the pointer to the
    \a item of the property as parameters. The passed \a item is
    deleted just after this call is finished.

    If the the parent of \a item is 0, the removed \a item was a
    top level property in this editor.

    This function must be reimplemented in derived classes. Note that
    if the removed \a item's property has subproperties, this
    method will be called for those properties just before the current call is started.

    \sa removeProperty()
*/

/*!
    \fn virtual void QtAbstractPropertyBrowser::itemChanged(QtBrowserItem *item) = 0

    This function is called whenever a property's data changes,
    passing a pointer to the \a item of property as parameter.

    This function must be reimplemented in derived classes in order to
    update the property browser widget whenever a property's name,
    tool tip, status tip, "what's this" text, value text or value icon
    changes.

    Note that if the property browser contains several occurrences of
    the same property, this method will be called once for each
    occurrence (with a different item each time).

    \sa QtProperty, items()
*/

/*!
    Creates an abstract property browser with the given \a parent.
*/
QtAbstractPropertyBrowser::QtAbstractPropertyBrowser(QWidget *parent)
    : QWidget(parent)
{
    d_ptr = new QtAbstractPropertyBrowserPrivate;
    d_ptr->q_ptr = this;

}

/*!
    Destroys the property browser, and destroys all the items that were
    created by this property browser.

    Note that the properties that were displayed in the editor are not
    deleted since they still can be used in other editors. Neither
    does the destructor delete the property managers and editor
    factories that were used by this property browser widget unless
    this widget was their parent.

    \sa QtAbstractPropertyManager::~QtAbstractPropertyManager()
*/
QtAbstractPropertyBrowser::~QtAbstractPropertyBrowser()
{
    QList<QtBrowserItem *> indexes = topLevelItems();
    QListIterator<QtBrowserItem *> itItem(indexes);
    while (itItem.hasNext())
        d_ptr->clearIndex(itItem.next());
    delete d_ptr;
}

/*!
    Returns the property browser's list of top level properties.

    To traverse the subproperties, use the QtProperty::subProperties()
    function.

    \sa addProperty(), insertProperty(), removeProperty()
*/
QList<QtProperty *> QtAbstractPropertyBrowser::properties() const
{
    return d_ptr->m_subItems;
}

/*!
    Returns the property browser's list of all items associated
    with the given \a property.

    There is one item per instance of the property in the browser.

    \sa topLevelItem()
*/

QList<QtBrowserItem *> QtAbstractPropertyBrowser::items(QtProperty *property) const
{
    return d_ptr->m_propertyToIndexes.value(property);
}

/*!
    Returns the top-level items associated with the given \a property.

    Returns 0 if \a property wasn't inserted into this property
    browser or isn't a top-level one.

    \sa topLevelItems(), items()
*/

QtBrowserItem *QtAbstractPropertyBrowser::topLevelItem(QtProperty *property) const
{
    return d_ptr->m_topLevelPropertyToIndex.value(property);
}

/*!
    Returns the list of top-level items.

    \sa topLevelItem()
*/

QList<QtBrowserItem *> QtAbstractPropertyBrowser::topLevelItems() const
{
    return d_ptr->m_topLevelIndexes;
}

/*!
    Removes all the properties from the editor, but does not delete
    them since they can still be used in other editors.

    \sa removeProperty(), QtAbstractPropertyManager::clear()
*/
void QtAbstractPropertyBrowser::clear()
{
    QList<QtProperty *> subList = properties();
    QListIterator<QtProperty *> itSub(subList);
    itSub.toBack();
    while (itSub.hasPrevious()) {
        QtProperty *property = itSub.previous();
        removeProperty(property);
    }
}

/*!
    Appends the given \a property (and its subproperties) to the
    property browser's list of top level properties. Returns the item
    created by property browser which is associated with the \a property.
    In order to get all children items created by the property
    browser in this call, the returned item should be traversed.

    If the specified \a property is already added, this function does
    nothing and returns 0.

    \sa insertProperty(), QtProperty::addSubProperty(), properties()
*/
QtBrowserItem *QtAbstractPropertyBrowser::addProperty(QtProperty *property)
{
    QtProperty *afterProperty = 0;
    if (d_ptr->m_subItems.count() > 0)
        afterProperty = d_ptr->m_subItems.last();
    return insertProperty(property, afterProperty);
}

/*!
    \fn QtBrowserItem *QtAbstractPropertyBrowser::insertProperty(QtProperty *property,
            QtProperty *afterProperty)

    Inserts the given \a property (and its subproperties) after
    the specified \a afterProperty in the browser's list of top
    level properties. Returns item created by property browser which
    is associated with the \a property. In order to get all children items
    created by the property browser in this call returned item should be traversed.

    If the specified \a afterProperty is 0, the given \a property is
    inserted at the beginning of the list.  If \a property is
    already inserted, this function does nothing and returns 0.

    \sa addProperty(), QtProperty::insertSubProperty(), properties()
*/
QtBrowserItem *QtAbstractPropertyBrowser::insertProperty(QtProperty *property,
            QtProperty *afterProperty)
{
    if (!property)
        return 0;

    // if item is already inserted in this item then cannot add.
    QList<QtProperty *> pendingList = properties();
    int pos = 0;
    int newPos = 0;
    //QtProperty *properAfterProperty = 0;
    while (pos < pendingList.count()) {
        QtProperty *prop = pendingList.at(pos);
        if (prop == property)
            return 0;
        if (prop == afterProperty) {
            newPos = pos + 1;
            //properAfterProperty = afterProperty;
        }
        pos++;
    }
    d_ptr->createBrowserIndexes(property, 0, afterProperty);

    // traverse inserted subtree and connect to manager's signals
    d_ptr->insertSubTree(property, 0);

    d_ptr->m_subItems.insert(newPos, property);
    //propertyInserted(property, 0, properAfterProperty);
    return topLevelItem(property);
}

/*!
    Removes the specified \a property (and its subproperties) from the
    property browser's list of top level properties. All items
    that were associated with the given \a property and its children
    are deleted.

    Note that the properties are \e not deleted since they can still
    be used in other editors.

    \sa clear(), QtProperty::removeSubProperty(), properties()
*/
void QtAbstractPropertyBrowser::removeProperty(QtProperty *property)
{
    if (!property)
        return;

    QList<QtProperty *> pendingList = properties();
    int pos = 0;
    while (pos < pendingList.count()) {
        if (pendingList.at(pos) == property) {
            d_ptr->m_subItems.removeAt(pos); //perhaps this two lines
            d_ptr->removeSubTree(property, 0); //should be moved down after propertyRemoved call.
            //propertyRemoved(property, 0);

            d_ptr->removeBrowserIndexes(property, 0);

            // when item is deleted, item will call removeItem for top level items,
            // and itemRemoved for nested items.

            return;
        }
        pos++;
    }
}

/*!
    Creates an editing widget (with the given \a parent) for the given
    \a property according to the previously established associations
    between property managers and editor factories.

    If the property is created by a property manager which was not
    associated with any of the existing factories in \e this property
    editor, the function returns 0.

    To make a property editable in the property browser, the
    createEditor() function must be called to provide the
    property with a suitable editing widget.

    Reimplement this function to provide additional decoration for the
    editing widgets created by the installed factories.

    \sa setFactoryForManager()
*/
QWidget *QtAbstractPropertyBrowser::createEditor(QtProperty *property,
                QWidget *parent)
{
    QtAbstractEditorFactoryBase *factory = 0;
    QtAbstractPropertyManager *manager = property->propertyManager();

    if (m_viewToManagerToFactory()->contains(this) &&
        (*m_viewToManagerToFactory())[this].contains(manager)) {
        factory = (*m_viewToManagerToFactory())[this][manager];
    }

    if (!factory)
        return 0;
    return factory->createEditor(property, parent);
}

bool QtAbstractPropertyBrowser::addFactory(QtAbstractPropertyManager *abstractManager,
            QtAbstractEditorFactoryBase *abstractFactory)
{
    bool connectNeeded = false;
    if (!m_managerToFactoryToViews()->contains(abstractManager) ||
        !(*m_managerToFactoryToViews())[abstractManager].contains(abstractFactory)) {
        connectNeeded = true;
    } else if ((*m_managerToFactoryToViews())[abstractManager][abstractFactory]
                    .contains(this)) {
        return connectNeeded;
    }

    if (m_viewToManagerToFactory()->contains(this) &&
        (*m_viewToManagerToFactory())[this].contains(abstractManager)) {
        unsetFactoryForManager(abstractManager);
    }

    (*m_managerToFactoryToViews())[abstractManager][abstractFactory].append(this);
    (*m_viewToManagerToFactory())[this][abstractManager] = abstractFactory;

    return connectNeeded;
}

/*!
    Removes the association between the given \a manager and the
    factory bound to it, automatically calling the
    QtAbstractEditorFactory::removePropertyManager() function if necessary.

    \sa setFactoryForManager()
*/
void QtAbstractPropertyBrowser::unsetFactoryForManager(QtAbstractPropertyManager *manager)
{
    if (!m_viewToManagerToFactory()->contains(this) ||
        !(*m_viewToManagerToFactory())[this].contains(manager)) {
        return;
    }

    QtAbstractEditorFactoryBase *abstractFactory =
                (*m_viewToManagerToFactory())[this][manager];
    (*m_viewToManagerToFactory())[this].remove(manager);
    if ((*m_viewToManagerToFactory())[this].isEmpty()) {
        (*m_viewToManagerToFactory()).remove(this);
    }

    (*m_managerToFactoryToViews())[manager][abstractFactory].removeAll(this);
    if ((*m_managerToFactoryToViews())[manager][abstractFactory].isEmpty()) {
        (*m_managerToFactoryToViews())[manager].remove(abstractFactory);
        abstractFactory->breakConnection(manager);
        if ((*m_managerToFactoryToViews())[manager].isEmpty()) {
            (*m_managerToFactoryToViews()).remove(manager);
        }
    }
}

/*!
    Returns the current item in the property browser.

    \sa setCurrentItem()
*/
QtBrowserItem *QtAbstractPropertyBrowser::currentItem() const
{
    return d_ptr->m_currentItem;
}

/*!
    Sets the current item in the property browser to \a item.

    \sa currentItem(), currentItemChanged()
*/
void QtAbstractPropertyBrowser::setCurrentItem(QtBrowserItem *item)
{
    QtBrowserItem *oldItem = d_ptr->m_currentItem;
    d_ptr->m_currentItem = item;
    if (oldItem != item)
        emit  currentItemChanged(item);
}

#if QT_VERSION >= 0x040400
QT_END_NAMESPACE
#endif

#include "moc_qtpropertybrowser.cpp"