예제 #1
0
static VALUE layout_move_to(VALUE self, VALUE x, VALUE y)
{
  int i;
  VALUE on_move, dx, dy;
  VALUE *pos = RSTRUCT_PTR(*(RSTRUCT_PTR(get_layout(self))));
  VALUE *pox = pos+0;
  VALUE *poy = pos+1;
  VALUE tx = *pox;
  VALUE ty = *poy;
  *pox = x;
  *poy = y;
  dx = INT2NUM((NUM2INT(x))-(NUM2INT(tx)));
  dy = INT2NUM((NUM2INT(y))-(NUM2INT(ty)));
  layout_update_layout(self, dx, dy);
  on_move = *(RSTRUCT_PTR(get_layout(self)) + 4);
  for(i=0; i<RARRAY_LEN(on_move); i++)
  {
    rb_funcall(*(RARRAY_PTR(on_move) + i), rb_intern("call"), 5, self, *pox, *poy, dx, dy);
  }
  if(rb_block_given_p() == Qtrue){
    VALUE ret = rb_yield(self);
    if(ret == Qnil || ret == Qfalse)
    {
      *pox = tx;
      *poy = ty;
      layout_update_layout(self, INT2NUM(-(NUM2INT(dx))), INT2NUM(-(NUM2INT(dy))));
    }
  }
  return self;
}
예제 #2
0
  int CoutAppender::_append (const log4tango::LoggingEvent& event)
  {
#ifdef _TG_WINDOWS_
    CoutBuf *dbg_win;
    try {
      dbg_win = Util::instance(false)->get_debug_object();
    } catch (...) {
      dbg_win = 0;
    }
    if (dbg_win)
      dbg_win->dbg_out(get_layout().format(event).c_str());
    else
#endif
      ::printf("%s\n", get_layout().format(event).c_str());
    return 0;
  }
예제 #3
0
void NumericalEntry::get_preferred_width_vfunc(int &minimum_width, int &natural_width) const
{
	Glib::RefPtr<Gtk::StyleContext> style_context = get_style_context();
	Glib::RefPtr<const Pango::Layout> layout = get_layout();
	Glib::RefPtr<Pango::Layout> layout_copy = Pango::Layout::create(layout->get_context());

	// measure width of a string containing the upper value
	string upper_str = format_for_value(_adjustment->get_upper());
	int upper_width = measure_string_width(layout_copy, upper_str);

	int width = max(upper_width, MIN_WIDTH);

	// measure width of a string containing the lower value
	string lower_str = format_for_value(_adjustment->get_lower());
	int lower_width = measure_string_width(layout_copy, lower_str);

	width = max(width, lower_width);

	// add borders
	Gtk::Border border = style_context->get_border();
	width += border.get_left() + border.get_right();

	// add paddings
	Gtk::Border padding = style_context->get_padding();
	width += padding.get_left() + padding.get_right();

	minimum_width = width;
	natural_width = width;
}
예제 #4
0
static VALUE layout_add_snap_child(VALUE self, VALUE spr)
{
  VALUE layout   = get_layout(self);
  VALUE snap     = *(RSTRUCT_PTR(layout)+3);
  VALUE children = *(RSTRUCT_PTR(snap)+1);
  if(rb_ary_includes(children, spr)==Qfalse){ rb_ary_push(children, spr); }
  return self;
}
예제 #5
0
파일: nilwm.c 프로젝트: nqv/nilwm
/** Swap focused client with next/prev/master one
 */
void swap(const struct arg_t *arg) {
    const struct layout_t *h;

    NIL_LOG("swap %d", nil_.ws_idx);
    h = get_layout(&nil_.ws[nil_.ws_idx]);
    if (h->swap) {
        (*h->swap)(&nil_.ws[nil_.ws_idx], arg->i);
    }
}
예제 #6
0
파일: nilwm.c 프로젝트: nqv/nilwm
/** Focus next/prev or master client
 */
void focus(const struct arg_t *arg) {
    const struct layout_t *h;

    NIL_LOG("focus %d", nil_.ws_idx);
    h = get_layout(&nil_.ws[nil_.ws_idx]);
    if (h->focus) {
        (*h->focus)(&nil_.ws[nil_.ws_idx], arg->i);
    }
}
예제 #7
0
파일: bar.c 프로젝트: nqv/nilwm
void update_bar_sym() {
    const char *sym;

    sym = (get_layout(&nil_.ws[nil_.ws_idx]))->symbol;
    if (!sym) {
        NIL_ERR("no layout symbol %d", nil_.ws_idx);
        return;
    }
    draw_bar_text(&bar_.box[BAR_SYM], sym, strlen(sym));
}
예제 #8
0
	// Creates the graphics pipeline object
	void create_pipeline() {
		// Vulkan shader stage descriptors
		auto shader_stage_descriptors = get_layout().shader_stage_descriptors();

		// Blend operation descriptor for each attachment
		lib::vector<vk::vk_blend_op_descriptor> attachment_blend_ops;
		for (auto &a : fb_layout) {
			const framebuffer_attachment_layout &attachment = a.second;

			// Blend operation is only applicable for color attachments
			const bool is_depth_attachment = format_is_depth(attachment.image_format);
			if (is_depth_attachment)
				continue;

			vk::vk_blend_op_descriptor desc = attachment.blend;
			attachment_blend_ops.push_back(std::move(desc));
		}

		// Set viewport and scissor as dynamic states
		lib::vector<VkDynamicState> dynamic_states = {
			static_cast<VkDynamicState>(pipeline_dynamic_state::viewport),
			static_cast<VkDynamicState>(pipeline_dynamic_state::scissor),
		};

		// Create the graphics pipeline object
		graphics_pipeline.emplace(ctx.get().device(),
								  shader_stage_descriptors,
								  get_layout(),
								  device_renderpass.get(),
								  0,
								  VkViewport{},
								  VkRect2D{},
								  vertex_input_descriptor.vertex_input_binding_descriptors,
								  vertex_input_descriptor.vertex_input_attribute_descriptors,
								  static_cast<VkPrimitiveTopology>(pipeline_settings.topology),
								  pipeline_settings.rasterizer_op,
								  pipeline_settings.depth_op,
								  attachment_blend_ops,
								  pipeline_settings.blend_constants,
								  dynamic_states,
								  pipeline_name.data(),
								  &ctx.get().device().pipeline_cache().current_thread_cache());
	}
예제 #9
0
static VALUE layout_update_layout(VALUE self, VALUE dx, VALUE dy)
{
  int i;
  VALUE layout, children;
  rb_funcall(self, rb_intern("update_layout_position"), 0);
  layout   = get_layout(self);
  children = *(RSTRUCT_PTR(*(RSTRUCT_PTR(layout)+3))+1);
  for(i=0; i<RARRAY_LEN(children); i++)
  {
    layout_move(*(RARRAY_PTR(children) + i), dx, dy);
  }
  return Qnil;
}
예제 #10
0
static VALUE layout_relative_move_to(VALUE self, VALUE x, VALUE y)
{
  int i;
  VALUE on_move, dx, dy;
  //      bpos = @layout.base.pos
  // Size.new(bpos.x+x,bpos.y+y)
  VALUE *pos = RSTRUCT_PTR(*(RSTRUCT_PTR(get_layout(self))));
  VALUE *pox = pos+0;
  VALUE *poy = pos+1;
  VALUE tx = *pox;
  VALUE ty = *poy;

  VALUE base = *(RSTRUCT_PTR(get_layout(self))+2);
  VALUE *bpos = RSTRUCT_PTR(rb_funcall(base, rb_intern("pos"), 0));

  *pox = INT2NUM(NUM2INT(x)+NUM2INT(*(bpos+0)));
  *poy = INT2NUM(NUM2INT(y)+NUM2INT(*(bpos+1)));

  dx = INT2NUM(NUM2INT(*pox)-NUM2INT(tx));
  dy = INT2NUM(NUM2INT(*poy)-NUM2INT(ty));
  layout_update_layout(self, dx, dy);
  on_move = *(RSTRUCT_PTR(get_layout(self)) + 4);
  for(i=0; i<RARRAY_LEN(on_move); i++)
  {
    rb_funcall(*(RARRAY_PTR(on_move) + i), rb_intern("call"), 5, self, *pox, *poy, dx, dy);
  }
  if(rb_block_given_p() == Qtrue){
    VALUE ret = rb_yield(self);
    if(ret == Qnil || ret == Qfalse)
    {
      *pox = tx;
      *poy = ty;
      layout_update_layout(self, INT2NUM(-(NUM2INT(dx))), INT2NUM(-(NUM2INT(dy))));
    }
  }
  return self;
}
예제 #11
0
static VALUE layout_delete_snap_child(VALUE self, VALUE spr)
{
  VALUE layout   = get_layout(self);
  VALUE snap     = *(RSTRUCT_PTR(layout)+3);
  VALUE children = *(RSTRUCT_PTR(snap)+1);
  if(TYPE(spr) == T_ARRAY)
  {
    int i;
    for(i=0; i<RARRAY_LEN(spr); i++){ rb_ary_delete(children, *(RARRAY_PTR(spr) + i)); }
  }
  else
  {
    rb_ary_delete(children, spr);
  }
  return self;
}
예제 #12
0
static void
draw_text (cairo_t *cr, int *width, int *height)
{

  PangoLayout *layout = get_layout (cr);

  /* Adds a fixed 10-pixel margin on the sides. */

  if (width || height)
    {
      pango_layout_get_pixel_size (layout, width, height);
      if (width)
        *width += 20;
      if (height)
        *height += 20;
    }

  cairo_move_to (cr, 10, 10);
  pango_cairo_show_layout (cr, layout);

  g_object_unref (layout);
}
예제 #13
0
static VALUE layout_snap(int argc, VALUE *argv, VALUE self)
{
  VALUE layout, *sprite, *base;
  VALUE spr = Qnil;
  rb_scan_args(argc, argv, "01", &spr);
  layout  = get_layout(self);
  sprite = RSTRUCT_PTR(*(RSTRUCT_PTR(layout)+3));
  base   = RSTRUCT_PTR(layout)+2;
  if(spr != Qnil)
  {
    if(*sprite != Qnil){ layout_delete_snap_child(*sprite, self); }
    *sprite = spr;
    layout_add_snap_child(spr, self);
  }
  if(*sprite != Qnil)
  {
    *base = *sprite;
  }
  else
  {
    *base = mScreen;
  }
  return self;
}
예제 #14
0
파일: event.c 프로젝트: nqv/nilwm
static
void handle_button_release(xcb_button_release_event_t *e) {
    const struct layout_t *h;

    NIL_LOG("event: mouse release %d", e->detail);
    mouse_evt_.x2 = e->event_x;
    mouse_evt_.y2 = e->event_y;

    h = get_layout(mouse_evt_.ws);
    switch (mouse_evt_.mode) {
    case CURSOR_MOVE:
        if (h->move) {
            (*h->move)(mouse_evt_.ws, &mouse_evt_);
        }
        break;
    case CURSOR_RESIZE:
        if (h->resize) {
            (*h->resize)(mouse_evt_.ws, &mouse_evt_);
        }
        break;
    }
    xcb_ungrab_pointer(nil_.con, XCB_CURRENT_TIME);
    xcb_flush(nil_.con);
}
예제 #15
0
static void initialize_place(struct level *level, struct layout *layout,
			     struct place *p)
{
	int x, y, is_clear;
	struct item *item;
	p->item = NULL;
	place_location(level, p, &x, &y);
	is_clear = is_place_clear(layout, x, y);
	switch (get_layout(layout, x + 1, y)) {
	case LAYOUT_SUPER_PAC_GUM:
		if (is_clear)
			p->item = clone_super_pacgum(level->items);
		else
			log_w("no room for super pac gum at (%d,%d).", x, y);
		break;
	case LAYOUT_BONUS:
		if (!is_clear) {
			log_w("no room for bonus at (%d,%d).", x, y);
			break;
		}
		level->bonus_place = p;
		p->item = clone_empty(level->items);
		break;
	case LAYOUT_PACMAN:
		if (!is_clear) {
			log_w("no room for pacman home at (%d,%d).", x, y);
			break;
		}
		p->item = clone_empty(level->items);
		if (level->pacman_home)
			log_w("ignored extra pacman home at (%d,%d).", x, y);
		else
			level->pacman_home = p;
		break;
	case LAYOUT_GHOSTS:
		if (!is_clear)
			log_w("ghosts den at (%d,%d) to be recovered.", x, y);
		p->item = clone_empty(level->items);
		if (level->ghosts_home)
			log_w("ignored extra ghosts den at (%d,%d).", x, y);
		else
			level->ghosts_home = p;
		break;
	case LAYOUT_TELEPORT:
		if (!(item = clone_teleport(level->items, p))) {
			log_w("ignored extra teleport at (%d,%d).", x, y);
			if (is_clear)
				p->item = clone_empty(level->items);
		} else if (is_clear)
			p->item = item;
		break;
	case LAYOUT_PAC_GUM_1:
	case LAYOUT_PAC_GUM_2:
		if (is_clear)
			p->item = clone_pacgum(level->items);
		break;
	case LAYOUT_EMPTY:
		if (is_clear)
			p->item = clone_empty(level->items);
		break;
	case LAYOUT_WALL:
		break;
	}
}
예제 #16
0
static int is_place_clear(struct layout *layout, int x, int y)
{
	return get_layout(layout, x, y) != LAYOUT_WALL &&
		get_layout(layout, x, y + 1) != LAYOUT_WALL &&
		get_layout(layout, x + 1, y + 1) != LAYOUT_WALL;
}
예제 #17
0
static VALUE layout_pos(VALUE self)
{
  return *(RSTRUCT_PTR(get_layout(self)));
}
예제 #18
0
int
main(int argc, char **argv)
{
    int c, error;
    int rflag, tflag, lflag, cflag, dflag, aflag, iflag, errflag,
        Dflag, Rflag, rtlacDRflag, sflag, bflag;
    char *copt, *aopt, *delay, *rate, *layout_name, *b_type, *freq_str;
    char *kbdname = KBD_DEVICE, *endptr = NULL;
    int kbd, freq_val;
    extern char *optarg;
    extern int optind;

    rflag = tflag = cflag = dflag = aflag = iflag = errflag = lflag =
            Dflag = Rflag = sflag = bflag = 0;
    copt = aopt = (char *)0;

    (void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)
#define	TEXT_DOMAIN	"SYS_TEST"
#endif
    (void) textdomain(TEXT_DOMAIN);

    while ((c = getopt(argc, argv, "rtlisc:a:d:D:R:b:")) != EOF) {
        switch (c) {
        case 'r':
            rflag++;
            break;
        case 't':
            tflag++;
            break;
        case 'l':
            lflag++;
            break;
        case 'i':
            iflag++;
            break;
        case 's':
            sflag++;
            break;
        case 'c':
            copt = optarg;
            cflag++;
            break;
        case 'a':
            aopt = optarg;
            aflag++;
            break;
        case 'd':
            kbdname = optarg;
            dflag++;
            break;
        case 'D':
            delay = optarg;
            Dflag++;
            break;
        case 'R':
            rate = optarg;
            Rflag++;
            break;
        case 'b':
            bflag++;
            break;
        case '?':
            errflag++;
            break;
        }
    }

    /*
     * Check for valid arguments:
     *
     * If argument parsing failed or if there are left-over
     * command line arguments(except -s and -b option),
     * then we're done now.
     */
    if (errflag != 0 || (sflag == 0 && bflag == 0 && argc != optind)) {
        usage();
        exit(1);
    }

    /*
     * kbd requires that the user specify either "-i" or "-s" or "-b" or
     * at least one of -[rtlacDR].  The "-d" option is, well, optional.
     * We don't care if it's there or not.
     */
    rtlacDRflag = rflag + tflag + lflag + aflag + cflag + Dflag + Rflag;
    if (!((iflag != 0 && sflag == 0 && bflag == 0 && rtlacDRflag == 0) ||
            (iflag == 0 && sflag != 0 && bflag == 0 && dflag == 0 &&
             rtlacDRflag == 0) ||
            (iflag == 0 && sflag == 0 && bflag == 0 && rtlacDRflag != 0) ||
            (iflag == 0 && sflag == 0 && bflag != 0 && rtlacDRflag == 0))) {
        usage();
        exit(1);
    }

    if (Dflag && atoi(delay) <= 0) {
        (void) fprintf(stderr, "Invalid arguments: -D %s\n", delay);
        usage();
        exit(1);
    }

    if (Rflag && atoi(rate) <= 0) {
        (void) fprintf(stderr, "Invalid arguments: -R %s\n", rate);
        usage();
        exit(1);
    }

    /*
     * Open the keyboard device
     */
    if ((kbd = open(kbdname, O_RDWR)) < 0) {
        perror("opening the keyboard");
        (void) fprintf(stderr, "kbd: Cannot open %s\n", kbdname);
        exit(1);
    }

    if (iflag) {
        kbd_defaults(kbd);
        exit(0);	/* A mutually exclusive option */
        /*NOTREACHED*/
    }

    if (tflag)
        (void) get_type(kbd);

    if (lflag)
        get_layout(kbd);

    if (cflag && (error = click(copt, kbd)) != 0)
        exit(error);

    if (rflag)
        reset(kbd);

    if (aflag && (error = abort_enable(aopt, kbd)) != 0)
        exit(error);

    if (Dflag && (error = set_repeat_delay(delay, kbd)) != 0)
        exit(error);

    if (Rflag && (error = set_repeat_rate(rate, kbd)) != 0)
        exit(error);

    if (sflag) {
        if (argc == optind) {
            layout_name = NULL;
        } else if (argc == (optind + 1)) {
            layout_name = argv[optind];
        } else {
            usage();
            exit(1);
        }

        if ((error = set_kbd_layout(kbd, layout_name)) != 0)
            exit(error);
    }

    if (bflag) {
        if (argc == optind) {
            b_type = "keyboard";
        } else if (argc == (optind + 1)) {
            b_type = argv[argc - 2];
        } else {
            usage();
            exit(1);
        }

        if (strcmp(b_type, "keyboard") && strcmp(b_type, "console")) {
            usage();
            exit(1);
        }

        freq_str = argv[argc - 1];
        errno = 0;
        freq_val = (int)strtol(freq_str, &endptr, 10);
        if (errno != 0 || endptr[0] != '\0') {
            usage();
            exit(1);
        }

        if (freq_val < 0 || freq_val > INT16_MAX) {
            (void) fprintf(stderr, "Invalid arguments: -b %s\n",
                           freq_str);
            (void) fprintf(stderr, "Frequency range: [0 - %d]\n",
                           INT16_MAX);
            exit(1);
        }

        if ((error = set_beep_freq(kbd, b_type, freq_val)) != 0)
            exit(1);
    }

    return (0);
}
예제 #19
0
  void ButtonBox::on_size_request(int& w_, int& h_)
  {
#ifdef NDEBUG
    testInvariant(TEST_EXPANDABLE_VISIBLE_COUNT);
#endif

    Container::on_size_request(w_, h_);

    ProxySizeRequest proxy_size_request(*this, w_, h_);

    _expandable_childrens_size_request  = 0;

    if(get_children().size()==0)
      return;

    _n_visible_children=0;

    _max_child_width  = _min_max_child_width;
    _max_child_height = _min_max_child_height;

    if(get_is_horizontal())
      exchange(_max_child_width, _max_child_height);

    for(BoxChildContainerList::iterator iter = _start_children.begin(); iter!=_end_children.end();)
    {
      if(iter==_start_children.end())
      {
        iter  = _end_children.begin();
        continue;
      }

      if(iter->child->is_visible())
      {
        ++_n_visible_children;

        ProxyChild proxy_child(*this, *iter->child);

        _max_child_width = MAX(_max_child_width , proxy_child.get_size_request_width());
        _max_child_height = MAX(_max_child_height , proxy_child.get_size_request_height());
      }

      ++iter;
    }

    if(get_layout()==BUTTONBOX_SPREAD)
      proxy_size_request.h() += (_n_visible_children+1) * _spacing;
    else
      proxy_size_request.h() += (_n_visible_children-1) * _spacing;
    proxy_size_request.h() += _max_child_height*_n_visible_children;
    proxy_size_request.w() += _max_child_width;

    _children_size_request_width  = w_;
    _children_size_request_height  = h_;

    if(get_is_horizontal())
    {
      exchange(_max_child_width, _max_child_height);
    }

#ifdef NDEBUG
    testInvariant(TEST_EXPANDABLE_VISIBLE_COUNT);
#endif
  }
예제 #20
0
  void ButtonBox::v_rearrange_children()
  {
#ifdef NDEBUG
    testInvariant(TEST_EXPANDABLE_VISIBLE_COUNT);
#endif

    ProxyContainer proxy_container(*this);

    if(is_custom_size_request())
    {
      int a, b;
      on_size_request(a,b);
    }

    if(_n_visible_children==0)
      return;

    Real inv_childrens_size_request = 1.f/Real(_expandable_childrens_size_request);
    Real additional_size = MAX(0.f, Real(proxy_container.get_height() - proxy_container.get_children_size_request_height()));
    Real single_space = additional_size;
    int x_pos;

    int max_child_w;
    int max_child_h;

    if(get_is_horizontal())
    {
      max_child_w = MAX(_max_child_height, _max_child_height);
      max_child_h = MAX(_max_child_width, _max_child_width);
    }else
    {
      max_child_w = MAX(_max_child_width, _max_child_width);
      max_child_h = MAX(_max_child_height, _max_child_height);
    }

    Real cursor  = get_border_width();

    ButtonBoxStyle l = get_layout();
    switch(get_layout())
    {
    case BUTTONBOX_EDGE:
      single_space = additional_size / Real(_n_visible_children-1);
      break;
    case BUTTONBOX_START:
      break;
    case BUTTONBOX_END:
      cursor  += additional_size;
      break;
    case BUTTONBOX_CENTER:
      cursor  += additional_size*0.5f;
      break;
    case BUTTONBOX_SPREAD:
    default:
      single_space = additional_size / Real(_n_visible_children+1);
    }

    x_pos = MAX(get_border_width(), (proxy_container.get_width()-max_child_w)/2);

    int i=0;

    for(BoxChildContainerList::iterator iter = _start_children.begin(); iter!=_end_children.end();)
    {
      if(iter==_start_children.end())
      {
        iter  = _end_children.begin();
        continue;
      }

      g_assert(iter->child);
      g_assert(iter->child->get_size_request_width()>=0);
      g_assert(iter->child->get_size_request_height()>=0);

      ProxyChild child(*this, *iter->child);

      if(iter->child->is_visible())
      {
        switch(get_layout())
        {
        case BUTTONBOX_EDGE:
          break;
        case BUTTONBOX_START:
        case BUTTONBOX_END:
        case BUTTONBOX_CENTER:
          break;
        case BUTTONBOX_SPREAD:
        default:
          cursor  += single_space;
          cursor  += get_spacing();
        }

        child.set_allocation(x_pos, round(cursor), max_child_w, max_child_h);
        cursor  += max_child_h;

        switch(get_layout())
        {
        case BUTTONBOX_EDGE:
          cursor  += single_space;
          cursor  += get_spacing();
          break;
        case BUTTONBOX_START:
        case BUTTONBOX_END:
        case BUTTONBOX_CENTER:
          cursor  += get_spacing();
          break;
        case BUTTONBOX_SPREAD:
        default:
          break;
        }

        ++i;
      }
      ++iter;
    }
  }
예제 #21
0
static VALUE layout_size(VALUE self)
{
  return *(RSTRUCT_PTR(get_layout(self))+1);
}
예제 #22
0
	operator VkPushConstantRange() const { return get_layout(); }
예제 #23
0
void render_group_symbolizer(group_symbolizer const& sym,
                             feature_impl & feature,
                             attributes const& vars,
                             proj_transform const& prj_trans,
                             box2d<double> const& clipping_extent,
                             renderer_common & common,
                             render_thunk_list_dispatch & render_thunks)
{
    // find all column names referenced in the group rules and symbolizers
    std::set<std::string> columns;
    group_attribute_collector column_collector(columns, false);
    column_collector(sym);

    auto props = get<group_symbolizer_properties_ptr>(sym, keys::group_properties);

    // create a new context for the sub features of this group
    context_ptr sub_feature_ctx = std::make_shared<mapnik::context_type>();

    // populate new context with column names referenced in the group rules and symbolizers
    for (auto const& col_name : columns)
    {
        sub_feature_ctx->push(col_name);
    }

    // keep track of the sub features that we'll want to symbolize
    // along with the group rules that they matched
    std::vector< std::pair<group_rule_ptr, feature_ptr> > matches;

    // create a copied 'virtual' common renderer for processing sub feature symbolizers
    // create an empty detector for it, so we are sure we won't hit anything
    virtual_renderer_common virtual_renderer(common);

    // keep track of which lists of render thunks correspond to
    // entries in the group_layout_manager.
    std::list<render_thunk_list> layout_thunks;

    // layout manager to store and arrange bboxes of matched features
    group_layout_manager layout_manager(props->get_layout());
    layout_manager.set_input_origin(common.width_ * 0.5, common.height_ * 0.5);

    // run feature or sub feature through the group rules & symbolizers
    // for each index value in the range
    value_integer start = get<value_integer>(sym, keys::start_column);
    value_integer end = start + get<value_integer>(sym, keys::num_columns);
    for (value_integer col_idx = start; col_idx < end; ++col_idx)
    {
        // create sub feature with indexed column values
        feature_ptr sub_feature = feature_factory::create(sub_feature_ctx, col_idx);

        // copy the necessary columns to sub feature
        for(auto const& col_name : columns)
        {
            if (col_name.find('%') != std::string::npos)
            {
                if (col_name.size() == 1)
                {
                    // column name is '%' by itself, so give the index as the value
                    sub_feature->put(col_name, col_idx);
                }
                else
                {
                    // indexed column
                    std::string col_idx_str;
                    if (mapnik::util::to_string(col_idx_str,col_idx))
                    {
                        std::string col_idx_name = col_name;
                        boost::replace_all(col_idx_name, "%", col_idx_str);
                        sub_feature->put(col_name, feature.get(col_idx_name));
                    }
                }
            }
            else
            {
                // non-indexed column
                sub_feature->put(col_name, feature.get(col_name));
            }
        }

        // add a single point geometry at pixel origin
        double x = common.width_ / 2.0, y = common.height_ / 2.0, z = 0.0;
        common.t_.backward(&x, &y);
        prj_trans.forward(x, y, z);
        // note that we choose a point in the middle of the screen to
        // try to ensure that we don't get edge artefacts due to any
        // symbolizers with avoid-edges set: only the avoid-edges of
        // the group symbolizer itself should matter.
        geometry::point<double> origin_pt(x,y);
        sub_feature->set_geometry(origin_pt);
        // get the layout for this set of properties
        for (auto const& rule : props->get_rules())
        {
             if (util::apply_visitor(evaluate<feature_impl,value_type,attributes>(*sub_feature,common.vars_),
                                               *(rule->get_filter())).to_bool())
             {
                // add matched rule and feature to the list of things to draw
                matches.emplace_back(rule, sub_feature);

                // construct a bounding box around all symbolizers for the matched rule
                box2d<double> bounds;
                render_thunk_list thunks;
                render_thunk_extractor extractor(bounds, thunks, *sub_feature, common.vars_, prj_trans,
                                                 virtual_renderer, clipping_extent);

                for (auto const& _sym : *rule)
                {
                    // TODO: construct layout and obtain bounding box
                    util::apply_visitor(extractor, _sym);
                }

                // add the bounding box to the layout manager
                layout_manager.add_member_bound_box(bounds);
                layout_thunks.emplace_back(std::move(thunks));
                break;
            }
        }
    }

    // create a symbolizer helper
    std::list<box_element> box_elements;

    for (size_t i = 0; i < matches.size(); ++i)
    {
        group_rule_ptr match_rule = matches[i].first;
        feature_ptr match_feature = matches[i].second;
        value_unicode_string rpt_key_value = "";

        // get repeat key from matched group rule
        expression_ptr rpt_key_expr = match_rule->get_repeat_key();

        // if no repeat key was defined, use default from group symbolizer
        if (!rpt_key_expr)
        {
            rpt_key_expr = get<expression_ptr>(sym, keys::repeat_key);
        }

        // evaluate the repeat key with the matched sub feature if we have one
        if (rpt_key_expr)
        {
            rpt_key_value = util::apply_visitor(
                evaluate<feature_impl,value_type,attributes>(*match_feature,common.vars_),
                    *rpt_key_expr).to_unicode();
        }
        box_elements.emplace_back(layout_manager.offset_box_at(i), rpt_key_value);
    }

    agg::trans_affine tr;
    auto transform = get_optional<transform_type>(sym, keys::geometry_transform);
    if (transform)
    {
        evaluate_transform(tr, feature, common.vars_, *transform, common.scale_factor_);
    }

    label_placement::placement_params params {
        prj_trans, common.t_, tr, sym, feature, vars,
        box2d<double>(0, 0, common.width_, common.height_), common.query_extent_,
        common.scale_factor_, common.symbol_cache_ };

    using traits = label_placement::group_symbolizer_traits;
    text_placement_info_ptr placement_info = mapnik::get<text_placements_ptr>(
        sym, keys::text_placements_)->get_placement_info(common.scale_factor_,
            feature, vars, common.symbol_cache_);
    group_layout_generator layout_generator(params,
        *common.detector_, common.font_manager_,
        *placement_info, box_elements);
    const label_placement_enum placement_type =
        layout_generator.get_text_props().label_placement;

    label_placement::finder<traits>::apply(placement_type, layout_generator, params);

    for (pixel_position const& pos : layout_generator.placements_)
    {
        size_t layout_i = 0;
        for (auto const& thunks : layout_thunks)
        {
            pixel_position const& offset = layout_manager.offset_at(layout_i);
            pixel_position render_offset = pos + offset;
            render_thunks.render_list(thunks, render_offset);
            ++layout_i;
        }
    }
}