예제 #1
0
void RegionChooser::motion_resize_region(int x, int y)
{
    const int w = get_width() - 1;
    Glib::RefPtr<Gdk::Window> window = get_window();

    int k = int(double(x) / w * 128.0 + 0.5);

    if (k < resize.min) k = resize.min;
    else if (k > resize.max) k = resize.max;

    if (k != resize.pos) {
        if (resize.mode == resize.undecided) {
            if (k < resize.pos) {
                // edit high limit of prev_region
                resize.max = resize.region->KeyRange.low;
                resize.region = resize.prev_region;
                resize.mode = resize.moving_high_limit;
            } else {
                // edit low limit of region
                resize.min = resize.prev_region->KeyRange.high + 1;
                resize.mode = resize.moving_low_limit;
            }
        }
        Glib::RefPtr<const Gdk::GC> black = get_style()->get_black_gc();
        Glib::RefPtr<const Gdk::GC> white = get_style()->get_white_gc();
        if (region == resize.region) {
            gc->set_foreground(red);
            white = gc;
        }
        Glib::RefPtr<const Gdk::GC> bg = get_style()->get_bg_gc(Gtk::STATE_NORMAL);
        int prevx = int(w * resize.pos / 128.0 + 0.5);
        x = int(w * k / 128.0 + 0.5);

        if (resize.mode == resize.moving_high_limit) {
            if (k > resize.pos) {
                window->draw_rectangle(white, true, prevx, 1, x - prevx, h1 - 2);
                window->draw_line(black, prevx, 0, x, 0);
                window->draw_line(black, prevx, h1 - 1, x, h1 - 1);
            } else {
                int xx = ((resize.pos == resize.max && resize.max != 128) ? 1 : 0);
                window->draw_rectangle(bg, true, x + 1, 0, prevx - x - xx, h1);
            }
        } else {
            if (k < resize.pos) {
                window->draw_rectangle(white, true, x + 1, 1, prevx - x, h1 - 2);
                window->draw_line(black, x, 0, prevx, 0);
                window->draw_line(black, x, h1 - 1, prevx, h1 - 1);
            } else {
                int xx = ((resize.pos == resize.min && resize.min != 0) ? 1 : 0);
                window->draw_rectangle(bg, true, prevx + xx, 0, x - prevx - xx, h1);
            }
        }
        window->draw_line(black, x, 1, x, h1 - 2);
        resize.pos = k;
    }
}
예제 #2
0
bool Creater::on_drawing_motion_notify(GdkEventMotion * event)
{
	if (event->state & GDK_BUTTON1_MASK)
	{
		if (cur_chars_.size() == 0)
			return false;
	
		// do not process redundent points
		if (event->x == last_x && event->y == last_y)
			return false;
		cur_char_->add_point(event->x, event->y);

		Glib::RefPtr<Gdk::Window> win = drawing_.get_window();
		Glib::RefPtr<Gdk::GC> gc = drawing_.get_style()->get_black_gc();

		gc->set_rgb_fg_color(colors[2]);
		win->draw_line(
			gc,
			event->x, event->y,
			last_x, last_y
		);

		last_x = event->x;
		last_y = event->y;
	}

	return false;
}
예제 #3
0
bool
Trainer::on_drawing_motion_notify(GdkEventMotion * event)
{
	if (event->state & GDK_BUTTON1_MASK)
	{
		// do not process redundent points
		if (event->x == last_x && event->y == last_y)
			return false;
		cur_char_.add_point(event->x, event->y);

		Glib::RefPtr<Gdk::Window> win = drawing_.get_window();
		Glib::RefPtr<Gdk::GC> gc = drawing_.get_style()->get_black_gc();

		gc->set_rgb_fg_color(colors[2]);
		win->draw_line(
			gc,
			static_cast<int>(event->x),
			static_cast<int>(event->y),
			last_x, last_y
		);

		last_x = static_cast<int>(event->x);
		last_y = static_cast<int>(event->y);
	}

	return false;
}
 void draw_line
 (
     Glib::RefPtr<Gdk::Drawable> & drawable,
     int x1, int y1, int x2, int y2
 )
 {
     drawable->draw_line(m_gc, x1, y1, x2, y2);
 }
 void draw_line
 (
     Glib::RefPtr<Gdk::Pixmap> & pixmap,
     int x1, int y1, int x2, int y2
 )
 {
     pixmap->draw_line(m_gc, x1, y1, x2, y2);
 }
예제 #6
0
void
Trainer::draw_character()
{
	Glib::RefPtr<Gdk::Window> win = drawing_.get_window();
	Glib::RefPtr<Gdk::GC> gc = drawing_.get_style()->get_black_gc();

	stroke_num = 0;
	for (chrasis::Stroke::iterator si = cur_char_.strokes_begin();
	     si != cur_char_.strokes_end();
	     ++si)
	{
		// draw the stroke body
		gc->set_rgb_fg_color(colors[2]);
		for (chrasis::Point::iterator pi = si->points_begin();
		     pi != si->points_end() - 1;
		     ++pi)
		{
			win->draw_line( gc,
				static_cast<int>(pi->x()),
				static_cast<int>(pi->y()),
				static_cast<int>((pi+1)->x()),
				static_cast<int>((pi+1)->y())
			);
		}

		// draw a number before each stroke
		stringstream ss;
		ss << ++stroke_num;
		Glib::RefPtr<Pango::Layout> num = create_pango_layout(ss.str());
		int lx, ly;
		num->get_size(lx, ly);
		win->draw_layout(
			gc,
			static_cast<int>(si->points_begin()->x() - lx / Pango::SCALE - 5),
			static_cast<int>(si->points_begin()->y() - ly / Pango::SCALE - 5),
			num
		);

		// enchant the beginning and ending points
		chrasis::Point::iterator pi[2] =
			{ si->points_begin(), si->points_end() - 1 };

		for (int i=0;i<2;++i)
		{
			gc->set_rgb_fg_color(colors[i]);
			win->draw_arc( gc, true,
				static_cast<int>(pi[i]->x() - 3),
				static_cast<int>(pi[i]->y() - 3),
				5, 5, 0, 23040);
		}
	}
}
예제 #7
0
void PaletteWindow::DrawGrid (Glib::RefPtr<Gdk::Window> area,
		Glib::RefPtr<Gdk::GC>& gc)
{
	gc->set_rgb_fg_color(Gdk::Color("black"));

	area->draw_rectangle(gc, true, 0, 0, 161, 161);

	gc->set_rgb_fg_color(Gdk::Color("white"));
	for (uint8_t c = 0; c <= 16; ++c)
	{
		area->draw_line(gc, c*10, 0, c*10, 161);
		area->draw_line(gc, 0, c*10, 161, c*10);
	}
}
예제 #8
0
void RegionChooser::motion_move_region(int x, int y)
{
    const int w = get_width() - 1;
    Glib::RefPtr<Gdk::Window> window = get_window();

    int k = int(double(x - move.from_x) / w * 128.0 + 0.5);
    if (k == move.pos) return;
    int new_k;
    bool new_touch_left;
    bool new_touch_right;
    int a = 0;
    if (k > move.pos) {
        for (gig::Region* r = regions.first() ; ; r = regions.next()) {
            if (r != region) {
                int b = r ? r->KeyRange.low : 128;

                // gap: from a to b (not inclusive b)

                if (region->KeyRange.high + move.pos >= b) {
                    // not found the current gap yet, just continue
                } else {

                    if (a > region->KeyRange.low + k) {
                        // this gap is too far to the right, break
                        break;
                    }

                    int newhigh = std::min(region->KeyRange.high + k, b - 1);
                    int newlo = newhigh - (region->KeyRange.high - region->KeyRange.low);

                    if (newlo >= a) {
                        // yes it fits - it's a candidate
                        new_k = newlo - region->KeyRange.low;
                        new_touch_left = a > 0 && a == newlo;
                        new_touch_right = b < 128 && newhigh + 1 == b;
                    }
                }
                if (!r) break;
                a = r->KeyRange.high + 1;
            }
        }
    } else {
        for (gig::Region* r = regions.first() ; ; r = regions.next()) {
            if (r != region) {
                int b = r ? r->KeyRange.low : 128;

                // gap from a to b (not inclusive b)

                if (region->KeyRange.high + k >= b) {
                    // not found the current gap yet, just continue
                } else {

                    if (a > region->KeyRange.low + move.pos) {
                        // this gap is too far to the right, break
                        break;
                    }

                    int newlo = std::max(region->KeyRange.low + k, a);
                    int newhigh = newlo + (region->KeyRange.high - region->KeyRange.low);

                    if (newhigh < b) {
                        // yes it fits - break as the first one is the best
                        new_k = newlo - region->KeyRange.low;
                        new_touch_left = a > 0 && a == newlo;
                        new_touch_right = b < 128 && newhigh + 1 == b;
                        break;
                    }
                }
                if (!r) break;
                a = r->KeyRange.high + 1;
            }
        }
    }
    k = new_k;
    if (k == move.pos) return;

    Glib::RefPtr<const Gdk::GC> bg = get_style()->get_bg_gc(Gtk::STATE_NORMAL);
    int prevx = int(w * (move.pos + region->KeyRange.low) / 128.0 + 0.5);
    x = int(w * (k + region->KeyRange.low) / 128.0 + 0.5);
    int prevx2 = int(w * (move.pos + region->KeyRange.high + 1) / 128.0 + 0.5);
    int x2 = int(w * (k + region->KeyRange.high + 1) / 128.0 + 0.5);
    Glib::RefPtr<const Gdk::GC> black = get_style()->get_black_gc();
    gc->set_foreground(red);

    if (!new_touch_left) window->draw_line(black, x, 1, x, h1 - 2);
    if (!new_touch_right) window->draw_line(black, x2, 1, x2, h1 - 2);

    if (k > move.pos) {
        window->draw_rectangle(bg, true, prevx + (move.touch_left ? 1 : 0), 0,
                               std::min(x, prevx2 + 1 - (move.touch_right ? 1 : 0)) -
                               (prevx + (move.touch_left ? 1 : 0)), h1);

        window->draw_line(black, std::max(x, prevx2 + 1), 0, x2, 0);
        window->draw_line(black, std::max(x, prevx2 + 1), h1 - 1, x2, h1 - 1);
        window->draw_rectangle(gc, true, std::max(x + 1, prevx2), 1,
                               x2 - std::max(x + 1, prevx2), h1 - 2);
    } else {
        window->draw_rectangle(bg, true, std::max(x2 + 1, prevx + (move.touch_left ? 1 : 0)), 0,
                               prevx2 + 1 - (move.touch_right ? 1 : 0) -
                               std::max(x2 + 1, prevx + (move.touch_left ? 1 : 0)), h1);

        window->draw_line(black, x, 0, std::min(x2, prevx - 1), 0);
        window->draw_line(black, x, h1 - 1, std::min(x2, prevx - 1), h1 - 1);

        window->draw_rectangle(gc, true, x + 1, 1, std::min(x2 - 1, prevx) - x, h1 - 2);
    }

    move.pos = k;
    move.touch_left = new_touch_left;
    move.touch_right = new_touch_right;
}
예제 #9
0
bool RegionChooser::on_expose_event(GdkEventExpose* event)
{
    Glib::RefPtr<Gdk::Window> window = get_window();
    window->clear();
    const int h = KEYBOARD_HEIGHT;
    const int w = get_width() - 1;
    const int bh = int(h * 0.55);

    Glib::RefPtr<const Gdk::GC> black = get_style()->get_black_gc();
    Glib::RefPtr<const Gdk::GC> white = get_style()->get_white_gc();

    window->draw_rectangle(black, false, 0, h1, w, h - 1);
    gc->set_foreground(grey1);
    int x1 = int(w * 20.5 / 128.0 + 0.5);
    int x2 = int(w * 109.5 / 128.0 + 0.5);
    window->draw_rectangle(gc, true, 1, h1 + 1,
                           x1 - 1, h - 2);
    window->draw_rectangle(white, true, x1 + 1, h1 + 1, x2 - x1 - 1, h - 2);
    window->draw_rectangle(gc, true, x2 + 1, h1 + 1,
                           w - x2 - 1, h - 2);
    for (int i = 0 ; i < 128 ; i++) {
        int note = (i + 3) % 12;
        int x = int(w * i / 128.0 + 0.5);

        if (note == 1 || note == 4 || note == 6 || note == 9 || note == 11) {
            int x2 = int(w * (i + 0.5) / 128.0 + 0.5);
            window->draw_line(black, x2, h1 + bh, x2, h1 + h);

            int x3 = int(w * (i + 1) / 128.0 + 0.5);
            window->draw_rectangle(black, true, x, h1 + 1, x3 - x + 1, bh);
        } else if (note == 3 || note == 8) {
            window->draw_line(black, x, h1 + 1, x, h1 + h);
        }
        if (note == 3) draw_digit(i);
    }

    if (instrument) {
        int i = 0;
        gig::Region *next_region;
        int x3 = -1;
        for (gig::Region *r = regions.first() ; r ; r = next_region) {

            if (x3 < 0) x3 = int(w * (r->KeyRange.low) / 128.0 + 0.5);
            next_region = regions.next();
            if (!next_region || r->KeyRange.high + 1 != next_region->KeyRange.low) {
                int x2 = int(w * (r->KeyRange.high + 1) / 128.0 + 0.5);
                window->draw_line(black, x3, 0, x2, 0);
                window->draw_line(black, x3, h1 - 1, x2, h1 - 1);
                window->draw_line(black, x2, 1, x2, h1 - 2);
                window->draw_rectangle(white, true, x3 + 1, 1, x2 - x3 - 1, h1 - 2);
                x3 = -1;
            }
            i++;
        }

        for (gig::Region *r = regions.first() ; r ; r = regions.next()) {
            int x = int(w * (r->KeyRange.low) / 128.0 + 0.5);
            window->draw_line(black, x, 1, x, h1 - 2);
        }

        if (region) {
            int x1 = int(w * (region->KeyRange.low) / 128.0 + 0.5);
            int x2 = int(w * (region->KeyRange.high + 1) / 128.0 + 0.5);
            gc->set_foreground(red);
            window->draw_rectangle(gc, true, x1 + 1, 1, x2 - x1 - 1, h1 - 2);
        }
    }
    return true;
}
 void draw_line_on_pixmap (int x1, int y1, int x2, int y2)
 {
     m_pixmap->draw_line(m_gc, x1, y1, x2, y2);
 }
 void draw_line (int x1, int y1, int x2, int y2)
 {
     m_window->draw_line(m_gc, x1, y1, x2, y2);
 }
예제 #12
0
void Creater::draw_character()
{
	if (cur_chars_.size() == 0)
		return;

	Glib::RefPtr<Gdk::Window> win = drawing_.get_window();
	Glib::RefPtr<Gdk::GC> gc = drawing_.get_style()->get_black_gc();

	stroke_num = 0;
	for (Stroke::iterator si = cur_char_->strokes_begin();
	     si != cur_char_->strokes_end();
	     ++si)
	{
		// draw the stroke body
		gc->set_rgb_fg_color(colors[2]);
		for (Point::iterator pi = si->points_begin();
		     pi != si->points_end() - 1;
		     ++pi)
		{
			win->draw_line( gc,
				pi->x(), pi->y(),
				(pi+1)->x(), (pi+1)->y());
		}

		// draw a number before each stroke
		stringstream ss;
		ss << ++stroke_num;
		Glib::RefPtr<Pango::Layout> num = create_pango_layout(ss.str());
		int lx, ly;
		num->get_size(lx, ly);
		win->draw_layout(
			gc,
			si->points_begin()->x() - lx / Pango::SCALE - 5,
			si->points_begin()->y() - ly / Pango::SCALE - 5,
			num
		);

		// enchant the beginning and ending points
		Point::iterator pi[2] =
			{ si->points_begin(), si->points_end() - 1 };

		for (int i=0;i<2;++i)
		{
			gc->set_rgb_fg_color(colors[i]);
			win->draw_arc( gc, true,
				pi[i]->x() - 3, pi[i]->y() - 3,
				5, 5, 0, 23040);
		}
	}

	// get the recognizer instance
	Recognizer & rec = Recognizer::Instance();

	stroke_num = 0;
	// draw the normalized version
	int scale = 100;
	Character nc = rec.normalize( *cur_char_ );
	for (Stroke::iterator si = nc.strokes_begin();
	     si != nc.strokes_end();
	     ++si)
	{
		gc->set_rgb_fg_color(colors[3]);
		for (Point::iterator pi = si->points_begin();
		     pi != si->points_end() - 1;
		     ++pi)
		{
			win->draw_line( gc,
				pi->x() * scale, pi->y() * scale,
				(pi+1)->x() * scale, (pi+1)->y() * scale);
			win->draw_arc( gc, true,
				pi->x() * scale - 3, pi->y() * scale - 3,
				5, 5, 0, 23040);
		}

		// draw a number before each stroke
		Glib::RefPtr<Pango::Layout> num =
			create_pango_layout(boost::lexical_cast<std::string>(++stroke_num));
		int lx, ly;
		num->get_size(lx, ly);
		win->draw_layout(
			gc,
			si->points_begin()->x() * scale - lx / Pango::SCALE - 5,
			si->points_begin()->y() * scale - ly / Pango::SCALE - 5,
			num
		);

		// enchant the beginning and ending points
		Point::iterator pi[2] =
			{ si->points_begin(), si->points_end() - 1 };

		for (int i=0;i<2;++i)
		{
			gc->set_rgb_fg_color(colors[i]);
			win->draw_arc( gc, true,
				pi[i]->x() * scale - 3, pi[i]->y() * scale - 3,
				5, 5, 0, 23040);
		}
	}

}
예제 #13
0
bool Widget_Timeslider::redraw(bool /*doublebuffer*/)
{
	Glib::RefPtr<Gdk::Window> window = get_window();

	if(!window) return false;

	Glib::RefPtr<Gdk::GC>	gc = Gdk::GC::create(window);
	if(!gc) return false;

	//synfig::info("Drawing Timeslider");
	//clear	and update to current values
	//invalidated = false;
	//update_times();

	//draw grey rectangle
	Gdk::Color	c("#7f7f7f");
	gc->set_rgb_fg_color(c);
	gc->set_background(c);

	//Get the data for the window and the params to draw it...
	int w = get_width(), h = get_height();

	window->draw_rectangle(gc,true,0,0,w,h);

	const double EPSILON = 1e-6;
	if(!adj_timescale || w == 0) return true;

	//Get the time information since we now know it's valid
	double 	start = adj_timescale->get_lower(),
			end = adj_timescale->get_upper(),
			current = adj_timescale->get_value();

	if(end-start < EPSILON) return true;

	//synfig::info("Drawing Lines");

	//draw all the time stuff
	double dtdp = (end - start)/get_width();
	double dpdt = 1/dtdp;

	//lines

	//Draw the time line...
	double tpx = (current-start)*dpdt;
	gc->set_rgb_fg_color(Gdk::Color("#ffaf00"));
	window->draw_line(gc,round_to_int(tpx),0,round_to_int(tpx),fullheight);

	//normal line/text color
	gc->set_rgb_fg_color(Gdk::Color("#333333"));

	int ifps = round_to_int(fps);
	if (ifps < 1) ifps = 1;

	std::vector<double> ranges;

	unsigned int pos = 0;

	// build a list of all the factors of the frame rate
	for (int i = 1; i*i <= ifps; i++)
		if ((ifps%i) == 0)
		{
			ranges.insert(ranges.begin()+pos, i/fps);
			if (i*i != ifps)
				ranges.insert(ranges.begin()+pos+1, ifps/i/fps);
			pos++;
		}

	// fill in any gaps where one factor is more than 2 times the previous
	std::vector<double>::iterator iter, next;
	pos = 0;
	for (pos = 0; pos < ranges.size()-1; pos++)
	{
		iter = ranges.begin()+pos;
		next = iter+1;
		if (*iter*2 < *next)
			ranges.insert(next, *iter*2);
	}

	double more_ranges[] = {
		2, 3, 5, 10, 20, 30, 60, 90, 120, 180,
		300, 600, 1200, 1800, 2700, 3600, 3600*2,
		3600*4, 3600*8, 3600*16, 3600*32, 3600*64,
		3600*128, 3600*256, 3600*512, 3600*1024 };

	ranges.insert(ranges.end(), more_ranges, more_ranges + sizeof(more_ranges)/sizeof(double));

	double lowerrange = dtdp*140, upperrange = dtdp*280;
	double midrange = (lowerrange + upperrange)/2;

	//find most ideal scale
	double scale;
	next = binary_find(ranges.begin(), ranges.end(), midrange);
	iter = next++;

	if (iter == ranges.end()) iter--;
	if (next == ranges.end()) next--;

	if (abs(*next - midrange) < abs(*iter - midrange))
		iter = next;

	scale = *iter;

	// subdivide into this many tick marks (8 or less)
	int subdiv = round_to_int(scale * ifps);

	if (subdiv > 8)
	{
		const int ideal = subdiv;

		// find a number of tick marks that nicely divides the scale
		// (5 minutes divided by 6 is 50s, but that's not 'nice' -
		//  5 ticks of 1m each is much simpler than 6 ticks of 50s)
		for (subdiv = 8; subdiv > 0; subdiv--)
			if ((ideal <= ifps*2       && (ideal % (subdiv           )) == 0) ||
				(ideal <= ifps*2*60    && (ideal % (subdiv*ifps      )) == 0) ||
				(ideal <= ifps*2*60*60 && (ideal % (subdiv*ifps*60   )) == 0) ||
				(true                  && (ideal % (subdiv*ifps*60*60)) == 0))
				break;

		// if we didn't find anything, use 4 ticks
		if (!subdiv)
			subdiv = 4;
	}

	time_per_tickmark = scale / subdiv;

	//get first valid line and its position in pixel space
	double time = 0;
	double pixel = 0;

	int sdindex = 0;

	double subr = scale / subdiv;

	//get its position inside...
	time = ceil(start/subr)*subr - start;
	pixel = time*dpdt;

	//absolute time of the line to be drawn
	time += start;

	{ //inside the big'n
		double t = (time/scale - floor(time/scale))*subdiv; // the difference from the big mark in 0:1
		//sdindex = (int)floor(t + 0.5); //get how far through the range it is...
		sdindex = round_to_int(t); //get how far through the range it is...
		if (sdindex == subdiv) sdindex = 0;

		//synfig::info("Extracted fr %.2lf -> %d", t, sdindex);
	}

	//synfig::info("Initial values: %.4lf t, %.1lf pixels, %d i", time,pixel,sdindex);

	//loop to draw
	const int heightbig = 12;
	const int heightsmall = 4;

	int width = get_width();
	while( pixel < width )
	{
		int xpx = round_to_int(pixel);

		//draw big
		if(sdindex == 0)
		{
			window->draw_line(gc,xpx,0,xpx,heightbig);
			//round the time to nearest frame and draw the text
			Time tm((double)time);
			if(get_global_fps()) tm.round(get_global_fps());
			Glib::ustring timecode(tm.get_string(get_global_fps(),App::get_time_format()));

			//gc->set_rgb_fg_color(Gdk::Color("#000000"));
			layout->set_text(timecode);
			Pango::AttrList attr_list;
			// Aproximately a font size of 8 pixels.
			// Pango::SCALE = 1024
			// create_attr_size waits a number in 1000th of pixels.
			// Should be user customizable in the future. Now it is fixed to 10
			Pango::AttrInt pango_size(Pango::Attribute::create_attr_size(Pango::SCALE*10));
			pango_size.set_start_index(0);
			pango_size.set_end_index(64);
			attr_list.change(pango_size);
			layout->set_attributes(attr_list);
			window->draw_layout(gc,xpx+2,0,layout);
		}else
		{
			window->draw_line(gc,xpx,0,xpx,heightsmall);
		}

		//increment time and position
		pixel += subr / dtdp;
		time += subr;

		//increment index
		if(++sdindex >= subdiv) sdindex -= subdiv;
	}

	return true;
}
예제 #14
0
bool DimRegionChooser::on_expose_event(GdkEventExpose* event)
{
    if (!region) return true;

    // This is where we draw on the window
    Glib::RefPtr<Gdk::Window> window = get_window();
    Glib::RefPtr<Pango::Context> context = get_pango_context();

    Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(context);

    window->clear();

    // draw labels on the left (reflecting the dimension type)
    int y = 0;
    double maxwidth = 0;
    for (int i = 0 ; i < region->Dimensions ; i++) {
        int nbZones = region->pDimensionDefinitions[i].zones;
        if (nbZones) {
            const char* dstr;
            char dstrbuf[10];
            switch (region->pDimensionDefinitions[i].dimension) {
            case gig::dimension_none: dstr="none"; break;
            case gig::dimension_samplechannel: dstr="samplechannel"; break;
            case gig::dimension_layer: dstr="layer"; break;
            case gig::dimension_velocity: dstr="velocity"; break;
            case gig::dimension_channelaftertouch: dstr="channelaftertouch"; break;
            case gig::dimension_releasetrigger: dstr="releasetrigger"; break;
            case gig::dimension_keyboard: dstr="keyboard"; break;
            case gig::dimension_roundrobin: dstr="roundrobin"; break;
            case gig::dimension_random: dstr="random"; break;
            case gig::dimension_smartmidi: dstr="smartmidi"; break;
            case gig::dimension_roundrobinkeyboard: dstr="roundrobinkeyboard"; break;
            case gig::dimension_modwheel: dstr="modwheel"; break;
            case gig::dimension_breath: dstr="breath"; break;
            case gig::dimension_foot: dstr="foot"; break;
            case gig::dimension_portamentotime: dstr="portamentotime"; break;
            case gig::dimension_effect1: dstr="effect1"; break;
            case gig::dimension_effect2: dstr="effect2"; break;
            case gig::dimension_genpurpose1: dstr="genpurpose1"; break;
            case gig::dimension_genpurpose2: dstr="genpurpose2"; break;
            case gig::dimension_genpurpose3: dstr="genpurpose3"; break;
            case gig::dimension_genpurpose4: dstr="genpurpose4"; break;
            case gig::dimension_sustainpedal: dstr="sustainpedal"; break;
            case gig::dimension_portamento: dstr="portamento"; break;
            case gig::dimension_sostenutopedal: dstr="sostenutopedal"; break;
            case gig::dimension_softpedal: dstr="softpedal"; break;
            case gig::dimension_genpurpose5: dstr="genpurpose5"; break;
            case gig::dimension_genpurpose6: dstr="genpurpose6"; break;
            case gig::dimension_genpurpose7: dstr="genpurpose7"; break;
            case gig::dimension_genpurpose8: dstr="genpurpose8"; break;
            case gig::dimension_effect1depth: dstr="effect1depth"; break;
            case gig::dimension_effect2depth: dstr="effect2depth"; break;
            case gig::dimension_effect3depth: dstr="effect3depth"; break;
            case gig::dimension_effect4depth: dstr="effect4depth"; break;
            case gig::dimension_effect5depth: dstr="effect5depth"; break;
            default:
                sprintf(dstrbuf, "%d",
                        region->pDimensionDefinitions[i].dimension);
                dstr = dstrbuf;
                break;
            }
            layout->set_text(dstr);

            Pango::Rectangle rectangle = layout->get_logical_extents();
            double text_w = double(rectangle.get_width()) / Pango::SCALE;
            if (text_w > maxwidth) maxwidth = text_w;
            double text_h = double(rectangle.get_height()) / Pango::SCALE;
            Glib::RefPtr<const Gdk::GC> fg = get_style()->get_fg_gc(get_state());
            window->draw_layout(fg, 4, int(y + (h - text_h) / 2 + 0.5), layout);

        }
        y += h;
    }

    // draw dimensions' zones areas
    y = 0;
    int bitpos = 0;
    label_width = int(maxwidth + 10);
    for (int i = 0 ; i < region->Dimensions ; i++) {
        int nbZones = region->pDimensionDefinitions[i].zones;
        if (nbZones) {
            // draw focus rectangle around dimension's label and zones
            if (has_focus() && focus_line == i) {
                Gdk::Rectangle farea(0, y, 150, 20);
                get_style()->paint_focus(window, get_state(), farea, *this, "",
                                         0, y, label_width, 20);
            }

            Glib::RefPtr<const Gdk::GC> black = get_style()->get_black_gc();
            // draw top and bottom lines of dimension's zones
            window->draw_line(black, label_width, y, w - 1, y);
            window->draw_line(black, w - 1, y + h - 1, label_width, y + h - 1);
            // erase whole dimension's zones area
            window->draw_rectangle(get_style()->get_white_gc(), true,
                                   label_width + 1, y + 1, (w - label_width - 2), h - 2);

            int c = 0;
            if (dimregno >= 0) {
                int mask = ~(((1 << region->pDimensionDefinitions[i].bits) - 1) << bitpos);
                c = dimregno & mask; // mask away this dimension
            }
            bool customsplits =
                ((region->pDimensionDefinitions[i].split_type == gig::split_type_normal &&
                 region->pDimensionRegions[c]->DimensionUpperLimits[i]) ||
                (region->pDimensionDefinitions[i].dimension == gig::dimension_velocity &&
                 region->pDimensionRegions[c]->VelocityUpperLimit));

            // draw dimension's zone borders
            if (customsplits) {
                window->draw_line(black, label_width, y + 1, label_width, y + h - 2);
                for (int j = 0 ; j < nbZones ; j++) {
                    gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];
                    int upperLimit = d->DimensionUpperLimits[i];
                    if (!upperLimit) upperLimit = d->VelocityUpperLimit;
                    int v = upperLimit + 1;
                    int x = int((w - label_width - 1) * v / 128.0 + 0.5);
                    window->draw_line(black, label_width + x, y + 1, label_width + x, y + h - 2);
                }
            } else {
                for (int j = 0 ; j <= nbZones ; j++) {
                    int x = int((w - label_width - 1) * j / double(nbZones) + 0.5);
                    window->draw_line(black, label_width + x, y + 1, label_width + x, y + h - 2);
                }
            }

            // draw fill for currently selected zone
            if (dimregno >= 0) {
                gc->set_foreground(red);
                int dr = (dimregno >> bitpos) & ((1 << region->pDimensionDefinitions[i].bits) - 1);
                if (customsplits) {
                    int x1 = 0;
                    for (int j = 0 ; j < nbZones ; j++) {
                        gig::DimensionRegion *d = region->pDimensionRegions[c + (j << bitpos)];
                        int upperLimit = d->DimensionUpperLimits[i];
                        if (!upperLimit) upperLimit = d->VelocityUpperLimit;
                        int v = upperLimit + 1;
                        int x2 = int((w - label_width - 1) * v / 128.0 + 0.5);
                        if (j == dr && x1 < x2) {
                            window->draw_rectangle(gc, true, label_width + x1 + 1, y + 1,
                                                   (x2 - x1) - 1, h - 2);
                            break;
                        }
                        x1 = x2;
                    }
                } else {
                    if (dr < nbZones) {
                        int x1 = int((w - label_width - 1) * dr / double(nbZones) + 0.5);
                        int x2 = int((w - label_width - 1) * (dr + 1) / double(nbZones) + 0.5);
                        window->draw_rectangle(gc, true, label_width + x1 + 1, y + 1,
                                               (x2 - x1) - 1, h - 2);
                    }
                }
            }

            y += h;
        }
        bitpos += region->pDimensionDefinitions[i].bits;
    }