void TrackEditorPattern::paint_cursor(GUI::Painter &p,int p_row) {


	int rowsize=get_row_height();
	int fontofs=(rowsize-get_font_height())/2;
	int textofs=p_row*rowsize+fontofs;
	int columnwidth=get_font_width()*4;

	int column=Editor::get_singleton()->get_cursor_col();
	int field=Editor::get_singleton()->get_cursor_field();

	int xofs=column*columnwidth+get_font_width();

	//xofs+=VisualSettings::get_singleton()->get_pattern_cursor_offset().x;
	//textofs+=VisualSettings::get_singleton()->get_pattern_cursor_offset().y;

	switch( Editor::get_singleton()->get_track_edit_mode() ) {

		case Editor::EDIT_MODE_FRONT: {

			xofs+=2*field*get_font_width();
		} break;
		case Editor::EDIT_MODE_BACK: {

			xofs+=get_font_width()+field*get_font_width();
		} break;
	}

	p.draw_stylebox( stylebox( SB_TRACK_EDITOR_CURSOR ), GUI::Point(xofs,textofs), GUI::Size( get_font_width(), get_font_height() ) );
	
}
void TrackEditorPattern::paint_row_lines(GUI::Painter &p) {

	int visible_rows=Editor::get_singleton()->get_window_rows()+1;
	int row_size=get_row_height();

	int font_w=get_font_width();
	
	
	for (int i=0;i<visible_rows;i++) {
		
		Tick tick=Editor::get_singleton()->get_row_ticks( Editor::get_singleton()->get_window_offset() + i );

		int from_x; 
		int width_x; 
			
		if (track->get_block_at_pos(Editor::get_singleton()->get_row_ticks( Editor::get_singleton()->get_window_offset()+i))>=0) {
			from_x = font_w;
			width_x = size.width-from_x*2;
		} else {
			from_x=0;
			width_x=size.width;
				
		}		
		if ( (tick % TICKS_PER_BEAT)==0 ) {//beat
			
			int block=track->find_block_at_pos( tick );
			bool paint=true;
			if ( block!=-1) {
				
				if (track->get_block_pos(block)==tick)
					paint=false;
				
				if (track->get_block_pos(block)+track->get_block(block)->get_length()==tick)
					paint=false;
				
			}
			
			
		
			if (song->get_bar_map().get_bar_beat(tick/TICKS_PER_BEAT)==0)  {
				p.draw_fill_rect(GUI::Point(from_x,i*row_size),GUI::Size(width_x,1),color(COLOR_PATTERN_BAR_LINE));
			} else  if (paint) {
				p.draw_fill_rect(GUI::Point(from_x,i*row_size),GUI::Size(width_x,1),color(COLOR_PATTERN_BEAT_LINE));
				
			}

		} else
			p.draw_fill_rect(GUI::Point(from_x,i*row_size),GUI::Size(width_x,1),color(COLOR_PATTERN_SUBBEAT_LINE));

		
		//p.drawGUI::Rect(0,i*row_size,size.width,0);


	}

}
void TrackEditorPattern::get_row_column_and_field(GUI::Point p_pos,int *p_row,int *p_column,int *p_field) {
	
	int rowsize=get_row_height();
	int columnwidth=get_font_width()*4;

	int click_x=p_pos.x;
	if (Editor::get_singleton()->get_track_edit_mode()==Editor::EDIT_MODE_FRONT)
		click_x+=get_font_width()/2; //makes clicking easier
	click_x-=get_font_width();
	if (click_x<0)
		click_x=0;

	*p_row=p_pos.y/get_row_height();
	*p_column= click_x / columnwidth;
	int col_x=click_x % columnwidth;
	*p_field=col_x*2/columnwidth;
	
	if (*p_column>=track->get_visible_columns()) {
		
		*p_column=track->get_visible_columns()-1;
		*p_field=1;
	}
		
}
/* Return a height at a row boundary of the GtkTreeView. */
static void
_gtk_source_completion_container_get_preferred_height (GtkWidget *widget,
						       gint	 *min_height,
						       gint	 *nat_height)
{
	GtkSourceCompletionContainer *container = GTK_SOURCE_COMPLETION_CONTAINER (widget);
	GtkWidget *child;
	GtkRequisition nat_size;
	gint height;

	child = gtk_bin_get_child (GTK_BIN (container));
	gtk_widget_get_preferred_size (child, NULL, &nat_size);

	if (nat_size.height <= MAX_HEIGHT)
	{
		height = nat_size.height;
	}
	else
	{
		gint row_height = get_row_height (container, nat_size.height);
		gint n_rows_allowed = row_height != 0 ? MAX_HEIGHT / row_height : 0;

		height = n_rows_allowed * row_height;
	}

	if (GTK_WIDGET_CLASS (_gtk_source_completion_container_parent_class)->get_preferred_height != NULL)
	{
		gint min_height_parent = 0;

		GTK_WIDGET_CLASS (_gtk_source_completion_container_parent_class)->get_preferred_height (widget,
													&min_height_parent,
													NULL);

		height = MAX (height, min_height_parent);
	}

	if (min_height != NULL)
	{
		*min_height = height;
	}

	if (nat_height != NULL)
	{
		*nat_height = height;
	}

	g_return_if_fail (height >= 0);
}
void TrackEditorPattern::paint_note_event( GUI::Painter& p, int p_row, NoteListElement & p_note, bool p_repeat ) {

	
	GUI::FontID f=font(FONT_TRACK_EDITOR);
	
	GUI::Color font_col=color(COLOR_PATTERN_FONT);
	GUI::Color font_col_repeat=color(COLOR_PATTERN_FONT_REPEAT);
	GUI::Color font_col_vol=color(COLOR_PATTERN_FONT_VOLUME);
	GUI::Color font_col_nofit=color(COLOR_PATTERN_FONT_NOFIT);

	
	int rowsize=get_row_height();
	int fontofs=constant(C_TRACK_EDITOR_ROW_MARGIN);
	int textofs=p_row*rowsize+fontofs+p.get_font_ascent(font(FONT_TRACK_EDITOR));
	int volofs=p_row*rowsize+fontofs+p.get_font_height( font(FONT_TRACK_EDITOR) ) + constant(C_TRACK_EDITOR_VOL_NOTE_BAR_SEPAATION);
	int notewidth=get_font_width()*3;
	int columnwidth=get_font_width()*4;

	int fontxofs=get_font_width()+p_note.pos.column*columnwidth;

	
	Tick row_ticks=Editor::get_singleton()->get_ticks_per_row();
	Tick note_ofs=p_note.pos.tick; //p_row*row_ticksp_note.pos.tick-Editor::get_singleton()->get_row_ticks( Editor::get_singleton()->get_window_offset() ); 
	
	
	if (note_ofs!=0) {
		int pix_ofs=(int)note_ofs*get_row_size()/(int)row_ticks;
		textofs+=pix_ofs;
		volofs+=pix_ofs;
		font_col=font_col_nofit;
		font_col_vol=font_col_nofit;
		font_col_repeat=font_col_vol;
		
	} 


	static char buf[4]={0,0,0,0};
	if (p_note.note.is_note()) {

		switch( Editor::get_singleton()->get_track_edit_mode() ) {

		case Editor::EDIT_MODE_FRONT: { // note


			int note=p_note.note.note % 12;
			int octave = p_note.note.note / 12;

			buf[0]=note_str[note][0];
			buf[1]=note_str[note][1];
			buf[2]=(octave>9)?('A'+(char)(octave-10)):('0'+octave);
			p.draw_text(f,GUI::Point(fontxofs,textofs),buf,font_col);
			// volume

			p.draw_fill_rect(GUI::Point(fontxofs,volofs),GUI::Size(notewidth,constant(C_TRACK_EDITOR_VOL_NOTE_BAR_HEIGHT)),color(COLOR_PATTERN_VOLUME_BG));
			int vol_w=(p_note.note.volume*notewidth)/PatternTrack::Note::MAX_VOLUME;
			p.draw_fill_rect(GUI::Point(fontxofs,volofs),GUI::Size(vol_w,constant(C_TRACK_EDITOR_VOL_NOTE_BAR_HEIGHT)),color(COLOR_PATTERN_VOLUME_BAR));

		} break;
		case Editor::EDIT_MODE_BACK: { // volume


			buf[0]=' ';
			buf[1]='0'+p_note.note.volume/10;
			buf[2]='0'+p_note.note.volume%10;
			p.draw_text(f,GUI::Point(fontxofs,textofs),buf,font_col_vol);

			p.draw_fill_rect(GUI::Point(fontxofs,volofs),GUI::Size(notewidth,constant(C_TRACK_EDITOR_VOL_NOTE_BAR_HEIGHT)),color(COLOR_PATTERN_NOTE_BG));
//check this color later
			int note_w=get_note_display_column_pos(notewidth,p_note.note.note);

			p.draw_fill_rect(GUI::Point(fontxofs+note_w,volofs),GUI::Size(2,constant(C_TRACK_EDITOR_VOL_NOTE_BAR_HEIGHT)),color(COLOR_PATTERN_NOTE_BAR));
		} break;


		}
		
		GUI::Color col=color(COLOR_PATTERN_SUBBEAT_LINE);
		p.draw_fill_rect(GUI::Point(fontxofs,volofs),GUI::Size(1,constant(C_TRACK_EDITOR_VOL_NOTE_BAR_HEIGHT)),col);
		p.draw_fill_rect(GUI::Point(size.width-fontxofs,volofs),GUI::Size(1,constant(C_TRACK_EDITOR_VOL_NOTE_BAR_HEIGHT)),col);
		
		
	} else if (p_note.note.is_note_off()) {

		buf[0]='*';
		buf[1]='*';
		buf[2]='*';
		p.draw_text(f,GUI::Point(fontxofs,textofs),buf,font_col);

	}

	// draw volume

	if (p_note.note.is_note()) {
	}



}
int TrackEditorPattern::get_row_size() {
	
	
	return get_row_height();
}
void TrackEditorPattern::draw(const GUI::Point& p_pos,const GUI::Size& p_size,const GUI::Rect& p_exposed) {

	Editor::get_singleton()->set_window_rows( p_size.height / get_row_height() );
		
	GUI::Painter &p=*get_painter();

//	p.set_clip_rect(false,p_exposed);
	//p.set_clip_rect(true,p_exposed);
	
	p.draw_fill_rect(GUI::Point(0,0),size,color(COLOR_PATTERN_BG));

	paint_frames(p);

	paint_selection(p,p_exposed.pos.y,p_exposed.pos.y+p_exposed.size.height);
	
	int visible_rows=Editor::get_singleton()->get_window_rows();

	for (int i=0;i<visible_rows;i++) {

		Tick from=Editor::get_singleton()->get_row_ticks( Editor::get_singleton()->get_window_offset() + i );
		Tick to=from+Editor::get_singleton()->get_ticks_per_row()-1;
		Tick adjust=0;

		/* Calculate Repeat, if exists */
		
		bool repeat=false;
		
		int blk_idx = track->get_block_at_pos( from );
		int prev=track->find_block_at_pos( from );
		
		if (blk_idx<0 && prev>=0 && track->get_block( prev )->is_repeat_enabled())
			repeat=true;
		//printf("row %i, blkidx %i , prev %i, repeat %i\n",i,blk_idx,prev,repeat);

		/* If repeat, adjust from and to */
		
		if (repeat) {
			
			Tick block_from=track->get_block_pos( prev );
			Tick block_len=track->get_block( prev )->get_length();
			
			Tick new_tick_from=block_from+(from-block_from)%block_len;
			
			adjust=from-new_tick_from;
			
			
			to=new_tick_from+(to-from);
			from=new_tick_from;
			

		}
		
		
		NoteList nl;
		 
		{ 
			int from_block=track->find_block_at_pos(from);
			int to_block=track->find_block_at_pos(to);
			
			for (int b=from_block;b<=to_block;b++) {
			
				if (b<0)
					continue;
					
				PatternTrack::PatternBlock *block = static_cast<PatternTrack::PatternBlock*>(track->get_block(b));
				Tick block_pos = track->get_block_pos(b);
				Tick block_len = block->get_length();
				
				if (block_pos+block_len < from )
					continue;
					
				int note_from,note_to;
				//printf("tick %i-%i, notes %i-%i\n",from,to,note_from,note_to);
				
				if (block->get_notes_in_local_range(from-block_pos,to-block_pos,&note_from,&note_to)) {
				
					for (int n=note_from;n<=note_to;n++) {
					
						NoteListElement nle;
						nle.pos=block->get_note_pos(n);
						nle.pos.tick=nle.pos.tick+block_pos-from;
						nle.note=block->get_note(n);
						nl.push_back(nle);	
					}
				}
				
			}
		}

		/* Then if repeat, adjust positions */
		
		NoteList::iterator I=nl.begin();
		
		if (repeat) {
		
			for(;I!=nl.end();I++) {
				I->pos.tick+=adjust;
			}
		}
		
		if (!nl.empty()) {

			paint_multiple_note_events( p,i , nl, repeat );
		}

		//paint_cursor(p,i);

	}

	paint_row_lines(p);

//	printf("focus %i, track %i, row %i (%i-%i)\n",(int)has_focus(),(int)Editor::get_singleton()->get_cursor_track(),(int)Editor::get_singleton()->get_cursor_row(),(int)Editor::get_singleton()->get_window_offset(),(int)(Editor::get_singleton()->get_window_offset()+visible_rows));
	if ( has_focus() && Editor::get_singleton()->get_cursor_track()==song->find_track_pos(track) &&
		    Editor::get_singleton()->get_cursor_row()>=Editor::get_singleton()->get_window_offset() &&
		    Editor::get_singleton()->get_cursor_row()<(Editor::get_singleton()->get_window_offset()+visible_rows)) {
				/* cursor is here */

		
		paint_cursor( p, Editor::get_singleton()->get_cursor_row()-Editor::get_singleton()->get_window_offset() );

	}
	



}
void TrackEditorPattern::paint_frames(GUI::Painter& p) {

	int begin_pos=-1;
	int old_block_idx=-1;
	int visible_rows=Editor::get_singleton()->get_window_rows();
	GUI::StyleBox sb=stylebox(SB_PATTERN_BLOCK);
	GUI::StyleBox sb_shared=stylebox(SB_PATTERN_BLOCK_SHARED);
	
	int last_block_idx=-1;
	for (int i=0;i<(visible_rows+3);i++) {
		Tick tick=Editor::get_singleton()->get_row_ticks( Editor::get_singleton()->get_window_offset() + i );
		int block_idx=track->get_block_at_pos(tick);
		if (block_idx!=last_block_idx && block_idx!=-1)
			last_block_idx=block_idx;
			

		bool begin=(block_idx!=-1 && track->get_block_pos(block_idx)==tick);

		if (block_idx!=-1 && i==0 && !begin) {

			begin_pos=-1;
		}

		if (i==0)
			old_block_idx=block_idx;

		bool end=((old_block_idx!=block_idx || i==(visible_rows+2)) && old_block_idx!=-1);
		
		old_block_idx=block_idx;

		if (end) {

			int row_size=get_row_height();
			int begin_h=begin_pos*row_size;
			int len_h=(i-begin_pos)*row_size;

			
			p.draw_stylebox(sb, GUI::Point(0,begin_h),GUI::Size(size.width,len_h));
			
			if (last_block_idx!=-1 && track->get_block(last_block_idx)->get_refcount()>1) {

				p.draw_stylebox(sb_shared, GUI::Point(0,begin_h),GUI::Size(size.width,len_h));
			}
		

		}

		if (begin)
			begin_pos=i;

	}

	
	for (int i=0;i<(track->get_visible_columns()-1);i++ ) {
		
		int font_width=get_font_width();
		int ofs=font_width/2+font_width*4*(i+1);	
		
		p.draw_fill_rect(GUI::Point(ofs,0),GUI::Size(1,size.height),color(COLOR_PATTERN_SUBBEAT_LINE));
	}
	
}