kconfig/lxdialog: support resize
In all dialogs now properly catch KEY_RESIZE and take proper action. In mconf try to behave sensibly when a dialog routine returns -ERRDISPLAYTOOSMALL. The original check for a screnn size of 80x19 is kept for now. It may make sense to remove it later, but thats anyway what much text is adjusted for. Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
This commit is contained in:
		
					parent
					
						
							
								f3cbcdc955
							
						
					
				
			
			
				commit
				
					
						c8dc68ad0f
					
				
			
		
					 8 changed files with 161 additions and 71 deletions
				
			
		|  | @ -125,6 +125,12 @@ int dialog_checklist(const char *title, const char *prompt, int height, | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| do_resize: | ||||
| 	if (getmaxy(stdscr) < (height + 6)) | ||||
| 		return -ERRDISPLAYTOOSMALL; | ||||
| 	if (getmaxx(stdscr) < (width + 6)) | ||||
| 		return -ERRDISPLAYTOOSMALL; | ||||
| 
 | ||||
| 	max_choice = MIN(list_height, item_count()); | ||||
| 
 | ||||
| 	/* center dialog box on screen */ | ||||
|  | @ -303,6 +309,11 @@ int dialog_checklist(const char *title, const char *prompt, int height, | |||
| 		case KEY_ESC: | ||||
| 			key = on_key_esc(dialog); | ||||
| 			break; | ||||
| 		case KEY_RESIZE: | ||||
| 			delwin(list); | ||||
| 			delwin(dialog); | ||||
| 			on_key_resize(); | ||||
| 			goto do_resize; | ||||
| 		} | ||||
| 
 | ||||
| 		/* Now, update everything... */ | ||||
|  |  | |||
|  | @ -86,6 +86,9 @@ | |||
| #define ACS_DARROW 'v' | ||||
| #endif | ||||
| 
 | ||||
| /* error return codes */ | ||||
| #define ERRDISPLAYTOOSMALL (KEY_MAX + 1) | ||||
| 
 | ||||
| /*
 | ||||
|  *   Color definitions | ||||
|  */ | ||||
|  | @ -181,6 +184,7 @@ int item_is_tag(char tag); | |||
| 
 | ||||
| /* generic key handlers */ | ||||
| int on_key_esc(WINDOW *win); | ||||
| int on_key_resize(void); | ||||
| 
 | ||||
| void init_dialog(const char *backtitle); | ||||
| void reset_dialog(void); | ||||
|  | @ -199,8 +203,8 @@ int dialog_yesno(const char *title, const char *prompt, int height, int width); | |||
| int dialog_msgbox(const char *title, const char *prompt, int height, | ||||
| 		  int width, int pause); | ||||
| int dialog_textbox(const char *title, const char *file, int height, int width); | ||||
| int dialog_menu(const char *title, const char *prompt, int height, int width, | ||||
| 		int menu_height, const void *selected, int *s_scroll); | ||||
| int dialog_menu(const char *title, const char *prompt, | ||||
| 		const void *selected, int *s_scroll); | ||||
| int dialog_checklist(const char *title, const char *prompt, int height, | ||||
| 		     int width, int list_height); | ||||
| extern char dialog_input_result[]; | ||||
|  |  | |||
|  | @ -49,6 +49,17 @@ int dialog_inputbox(const char *title, const char *prompt, int height, int width | |||
| 	char *instr = dialog_input_result; | ||||
| 	WINDOW *dialog; | ||||
| 
 | ||||
| 	if (!init) | ||||
| 		instr[0] = '\0'; | ||||
| 	else | ||||
| 		strcpy(instr, init); | ||||
| 
 | ||||
| do_resize: | ||||
| 	if (getmaxy(stdscr) <= (height - 2)) | ||||
| 		return -ERRDISPLAYTOOSMALL; | ||||
| 	if (getmaxx(stdscr) <= (width - 2)) | ||||
| 		return -ERRDISPLAYTOOSMALL; | ||||
| 
 | ||||
| 	/* center dialog box on screen */ | ||||
| 	x = (COLS - width) / 2; | ||||
| 	y = (LINES - height) / 2; | ||||
|  | @ -86,11 +97,6 @@ int dialog_inputbox(const char *title, const char *prompt, int height, int width | |||
| 	wmove(dialog, box_y, box_x); | ||||
| 	wattrset(dialog, dlg.inputbox.atr); | ||||
| 
 | ||||
| 	if (!init) | ||||
| 		instr[0] = '\0'; | ||||
| 	else | ||||
| 		strcpy(instr, init); | ||||
| 
 | ||||
| 	input_x = strlen(instr); | ||||
| 
 | ||||
| 	if (input_x >= box_width) { | ||||
|  | @ -220,6 +226,10 @@ int dialog_inputbox(const char *title, const char *prompt, int height, int width | |||
| 		case KEY_ESC: | ||||
| 			key = on_key_esc(dialog); | ||||
| 			break; | ||||
| 		case KEY_RESIZE: | ||||
| 			delwin(dialog); | ||||
| 			on_key_resize(); | ||||
| 			goto do_resize; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -179,14 +179,25 @@ static void do_scroll(WINDOW *win, int *scroll, int n) | |||
| /*
 | ||||
|  * Display a menu for choosing among a number of options | ||||
|  */ | ||||
| int dialog_menu(const char *title, const char *prompt, int height, int width, | ||||
|                 int menu_height, const void *selected, int *s_scroll) | ||||
| int dialog_menu(const char *title, const char *prompt, | ||||
|                 const void *selected, int *s_scroll) | ||||
| { | ||||
| 	int i, j, x, y, box_x, box_y; | ||||
| 	int height, width, menu_height; | ||||
| 	int key = 0, button = 0, scroll = 0, choice = 0; | ||||
| 	int first_item =  0, max_choice; | ||||
| 	WINDOW *dialog, *menu; | ||||
| 
 | ||||
| do_resize: | ||||
| 	height = getmaxy(stdscr); | ||||
| 	width = getmaxx(stdscr); | ||||
| 	if (height < 15 || width < 65) | ||||
| 		return -ERRDISPLAYTOOSMALL; | ||||
| 
 | ||||
| 	height -= 4; | ||||
| 	width  -= 5; | ||||
| 	menu_height = height - 10; | ||||
| 
 | ||||
| 	max_choice = MIN(menu_height, item_count()); | ||||
| 
 | ||||
| 	/* center dialog box on screen */ | ||||
|  | @ -226,7 +237,10 @@ int dialog_menu(const char *title, const char *prompt, int height, int width, | |||
| 	draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2, | ||||
| 		 dlg.menubox_border.atr, dlg.menubox.atr); | ||||
| 
 | ||||
| 	item_x = (menu_width - 70) / 2; | ||||
| 	if (menu_width >= 80) | ||||
| 		item_x = (menu_width - 70) / 2; | ||||
| 	else | ||||
| 		item_x = 4; | ||||
| 
 | ||||
| 	/* Set choice to default item */ | ||||
| 	item_foreach() | ||||
|  | @ -407,6 +421,11 @@ int dialog_menu(const char *title, const char *prompt, int height, int width, | |||
| 		case KEY_ESC: | ||||
| 			key = on_key_esc(menu); | ||||
| 			break; | ||||
| 		case KEY_RESIZE: | ||||
| 			on_key_resize(); | ||||
| 			delwin(menu); | ||||
| 			delwin(dialog); | ||||
| 			goto do_resize; | ||||
| 		} | ||||
| 	} | ||||
| 	delwin(menu); | ||||
|  |  | |||
|  | @ -25,22 +25,36 @@ static void back_lines(int n); | |||
| static void print_page(WINDOW * win, int height, int width); | ||||
| static void print_line(WINDOW * win, int row, int width); | ||||
| static char *get_line(void); | ||||
| static void print_position(WINDOW * win, int height, int width); | ||||
| static void print_position(WINDOW * win); | ||||
| 
 | ||||
| static int hscroll; | ||||
| static int begin_reached, end_reached, page_length; | ||||
| static const char *buf; | ||||
| static const char *page; | ||||
| 
 | ||||
| /*
 | ||||
|  * refresh window content | ||||
|  */ | ||||
| static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw, | ||||
| 							  int cur_y, int cur_x) | ||||
| { | ||||
| 	print_page(box, boxh, boxw); | ||||
| 	print_position(dialog); | ||||
| 	wmove(dialog, cur_y, cur_x);	/* Restore cursor position */ | ||||
| 	wrefresh(dialog); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|  * Display text from a file in a dialog box. | ||||
|  */ | ||||
| int dialog_textbox(const char *title, const char *tbuf, int height, int width) | ||||
| int dialog_textbox(const char *title, const char *tbuf, | ||||
| 		   int initial_height, int initial_width) | ||||
| { | ||||
| 	int i, x, y, cur_x, cur_y, key = 0; | ||||
| 	int texth, textw; | ||||
| 	int height, width, boxh, boxw; | ||||
| 	int passed_end; | ||||
| 	WINDOW *dialog, *text; | ||||
| 	WINDOW *dialog, *box; | ||||
| 
 | ||||
| 	begin_reached = 1; | ||||
| 	end_reached = 0; | ||||
|  | @ -49,6 +63,25 @@ int dialog_textbox(const char *title, const char *tbuf, int height, int width) | |||
| 	buf = tbuf; | ||||
| 	page = buf;	/* page is pointer to start of page to be displayed */ | ||||
| 
 | ||||
| do_resize: | ||||
| 	getmaxyx(stdscr, height, width); | ||||
| 	if (height < 8 || width < 8) | ||||
| 		return -ERRDISPLAYTOOSMALL; | ||||
| 	if (initial_height != 0) | ||||
| 		height = initial_height; | ||||
| 	else | ||||
| 		if (height > 4) | ||||
| 			height -= 4; | ||||
| 		else | ||||
| 			height = 0; | ||||
| 	if (initial_width != 0) | ||||
| 		width = initial_width; | ||||
| 	else | ||||
| 		if (width > 5) | ||||
| 			width -= 5; | ||||
| 		else | ||||
| 			width = 0; | ||||
| 
 | ||||
| 	/* center dialog box on screen */ | ||||
| 	x = (COLS - width) / 2; | ||||
| 	y = (LINES - height) / 2; | ||||
|  | @ -58,14 +91,14 @@ int dialog_textbox(const char *title, const char *tbuf, int height, int width) | |||
| 	dialog = newwin(height, width, y, x); | ||||
| 	keypad(dialog, TRUE); | ||||
| 
 | ||||
| 	/* Create window for text region, used for scrolling text */ | ||||
| 	texth = height - 4; | ||||
| 	textw = width - 2; | ||||
| 	text = subwin(dialog, texth, textw, y + 1, x + 1); | ||||
| 	wattrset(text, dlg.dialog.atr); | ||||
| 	wbkgdset(text, dlg.dialog.atr & A_COLOR); | ||||
| 	/* Create window for box region, used for scrolling text */ | ||||
| 	boxh = height - 4; | ||||
| 	boxw = width - 2; | ||||
| 	box = subwin(dialog, boxh, boxw, y + 1, x + 1); | ||||
| 	wattrset(box, dlg.dialog.atr); | ||||
| 	wbkgdset(box, dlg.dialog.atr & A_COLOR); | ||||
| 
 | ||||
| 	keypad(text, TRUE); | ||||
| 	keypad(box, TRUE); | ||||
| 
 | ||||
| 	/* register the new window, along with its borders */ | ||||
| 	draw_box(dialog, 0, 0, height, width, | ||||
|  | @ -86,11 +119,8 @@ int dialog_textbox(const char *title, const char *tbuf, int height, int width) | |||
| 	getyx(dialog, cur_y, cur_x);	/* Save cursor position */ | ||||
| 
 | ||||
| 	/* Print first page of text */ | ||||
| 	attr_clear(text, texth, textw, dlg.dialog.atr); | ||||
| 	print_page(text, texth, textw); | ||||
| 	print_position(dialog, height, width); | ||||
| 	wmove(dialog, cur_y, cur_x);	/* Restore cursor position */ | ||||
| 	wrefresh(dialog); | ||||
| 	attr_clear(box, boxh, boxw, dlg.dialog.atr); | ||||
| 	refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); | ||||
| 
 | ||||
| 	while ((key != KEY_ESC) && (key != '\n')) { | ||||
| 		key = wgetch(dialog); | ||||
|  | @ -99,7 +129,7 @@ int dialog_textbox(const char *title, const char *tbuf, int height, int width) | |||
| 		case 'e': | ||||
| 		case 'X': | ||||
| 		case 'x': | ||||
| 			delwin(text); | ||||
| 			delwin(box); | ||||
| 			delwin(dialog); | ||||
| 			return 0; | ||||
| 		case 'g':	/* First page */ | ||||
|  | @ -107,10 +137,8 @@ int dialog_textbox(const char *title, const char *tbuf, int height, int width) | |||
| 			if (!begin_reached) { | ||||
| 				begin_reached = 1; | ||||
| 				page = buf; | ||||
| 				print_page(text, texth, textw); | ||||
| 				print_position(dialog, height, width); | ||||
| 				wmove(dialog, cur_y, cur_x);	/* Restore cursor position */ | ||||
| 				wrefresh(dialog); | ||||
| 				refresh_text_box(dialog, box, boxh, boxw, | ||||
| 						 cur_y, cur_x); | ||||
| 			} | ||||
| 			break; | ||||
| 		case 'G':	/* Last page */ | ||||
|  | @ -119,11 +147,9 @@ int dialog_textbox(const char *title, const char *tbuf, int height, int width) | |||
| 			end_reached = 1; | ||||
| 			/* point to last char in buf */ | ||||
| 			page = buf + strlen(buf); | ||||
| 			back_lines(texth); | ||||
| 			print_page(text, texth, textw); | ||||
| 			print_position(dialog, height, width); | ||||
| 			wmove(dialog, cur_y, cur_x);	/* Restore cursor position */ | ||||
| 			wrefresh(dialog); | ||||
| 			back_lines(boxh); | ||||
| 			refresh_text_box(dialog, box, boxh, boxw, | ||||
| 					 cur_y, cur_x); | ||||
| 			break; | ||||
| 		case 'K':	/* Previous line */ | ||||
| 		case 'k': | ||||
|  | @ -138,16 +164,16 @@ int dialog_textbox(const char *title, const char *tbuf, int height, int width) | |||
| 				 * point to start of next page. This is done | ||||
| 				 * by calling get_line() in the following | ||||
| 				 * 'for' loop. */ | ||||
| 				scrollok(text, TRUE); | ||||
| 				wscrl(text, -1);	/* Scroll text region down one line */ | ||||
| 				scrollok(text, FALSE); | ||||
| 				scrollok(box, TRUE); | ||||
| 				wscrl(box, -1);	/* Scroll box region down one line */ | ||||
| 				scrollok(box, FALSE); | ||||
| 				page_length = 0; | ||||
| 				passed_end = 0; | ||||
| 				for (i = 0; i < texth; i++) { | ||||
| 				for (i = 0; i < boxh; i++) { | ||||
| 					if (!i) { | ||||
| 						/* print first line of page */ | ||||
| 						print_line(text, 0, textw); | ||||
| 						wnoutrefresh(text); | ||||
| 						print_line(box, 0, boxw); | ||||
| 						wnoutrefresh(box); | ||||
| 					} else | ||||
| 						/* Called to update 'end_reached' and 'page' */ | ||||
| 						get_line(); | ||||
|  | @ -157,7 +183,7 @@ int dialog_textbox(const char *title, const char *tbuf, int height, int width) | |||
| 						passed_end = 1; | ||||
| 				} | ||||
| 
 | ||||
| 				print_position(dialog, height, width); | ||||
| 				print_position(dialog); | ||||
| 				wmove(dialog, cur_y, cur_x);	/* Restore cursor position */ | ||||
| 				wrefresh(dialog); | ||||
| 			} | ||||
|  | @ -167,23 +193,21 @@ int dialog_textbox(const char *title, const char *tbuf, int height, int width) | |||
| 		case KEY_PPAGE: | ||||
| 			if (begin_reached) | ||||
| 				break; | ||||
| 			back_lines(page_length + texth); | ||||
| 			print_page(text, texth, textw); | ||||
| 			print_position(dialog, height, width); | ||||
| 			wmove(dialog, cur_y, cur_x); | ||||
| 			wrefresh(dialog); | ||||
| 			back_lines(page_length + boxh); | ||||
| 			refresh_text_box(dialog, box, boxh, boxw, | ||||
| 					 cur_y, cur_x); | ||||
| 			break; | ||||
| 		case 'J':	/* Next line */ | ||||
| 		case 'j': | ||||
| 		case KEY_DOWN: | ||||
| 			if (!end_reached) { | ||||
| 				begin_reached = 0; | ||||
| 				scrollok(text, TRUE); | ||||
| 				scroll(text);	/* Scroll text region up one line */ | ||||
| 				scrollok(text, FALSE); | ||||
| 				print_line(text, texth - 1, textw); | ||||
| 				wnoutrefresh(text); | ||||
| 				print_position(dialog, height, width); | ||||
| 				scrollok(box, TRUE); | ||||
| 				scroll(box);	/* Scroll box region up one line */ | ||||
| 				scrollok(box, FALSE); | ||||
| 				print_line(box, boxh - 1, boxw); | ||||
| 				wnoutrefresh(box); | ||||
| 				print_position(dialog); | ||||
| 				wmove(dialog, cur_y, cur_x);	/* Restore cursor position */ | ||||
| 				wrefresh(dialog); | ||||
| 			} | ||||
|  | @ -194,10 +218,8 @@ int dialog_textbox(const char *title, const char *tbuf, int height, int width) | |||
| 				break; | ||||
| 
 | ||||
| 			begin_reached = 0; | ||||
| 			print_page(text, texth, textw); | ||||
| 			print_position(dialog, height, width); | ||||
| 			wmove(dialog, cur_y, cur_x); | ||||
| 			wrefresh(dialog); | ||||
| 			refresh_text_box(dialog, box, boxh, boxw, | ||||
| 					 cur_y, cur_x); | ||||
| 			break; | ||||
| 		case '0':	/* Beginning of line */ | ||||
| 		case 'H':	/* Scroll left */ | ||||
|  | @ -212,9 +234,8 @@ int dialog_textbox(const char *title, const char *tbuf, int height, int width) | |||
| 				hscroll--; | ||||
| 			/* Reprint current page to scroll horizontally */ | ||||
| 			back_lines(page_length); | ||||
| 			print_page(text, texth, textw); | ||||
| 			wmove(dialog, cur_y, cur_x); | ||||
| 			wrefresh(dialog); | ||||
| 			refresh_text_box(dialog, box, boxh, boxw, | ||||
| 					 cur_y, cur_x); | ||||
| 			break; | ||||
| 		case 'L':	/* Scroll right */ | ||||
| 		case 'l': | ||||
|  | @ -224,16 +245,21 @@ int dialog_textbox(const char *title, const char *tbuf, int height, int width) | |||
| 			hscroll++; | ||||
| 			/* Reprint current page to scroll horizontally */ | ||||
| 			back_lines(page_length); | ||||
| 			print_page(text, texth, textw); | ||||
| 			wmove(dialog, cur_y, cur_x); | ||||
| 			wrefresh(dialog); | ||||
| 			refresh_text_box(dialog, box, boxh, boxw, | ||||
| 					 cur_y, cur_x); | ||||
| 			break; | ||||
| 		case KEY_ESC: | ||||
| 			key = on_key_esc(dialog); | ||||
| 			break; | ||||
| 		case KEY_RESIZE: | ||||
| 			back_lines(height); | ||||
| 			delwin(box); | ||||
| 			delwin(dialog); | ||||
| 			on_key_resize(); | ||||
| 			goto do_resize; | ||||
| 		} | ||||
| 	} | ||||
| 	delwin(text); | ||||
| 	delwin(box); | ||||
| 	delwin(dialog); | ||||
| 	return key;		/* ESC pressed */ | ||||
| } | ||||
|  | @ -353,13 +379,13 @@ static char *get_line(void) | |||
| /*
 | ||||
|  * Print current position | ||||
|  */ | ||||
| static void print_position(WINDOW * win, int height, int width) | ||||
| static void print_position(WINDOW * win) | ||||
| { | ||||
| 	int percent; | ||||
| 
 | ||||
| 	wattrset(win, dlg.position_indicator.atr); | ||||
| 	wbkgdset(win, dlg.position_indicator.atr & A_COLOR); | ||||
| 	percent = (page - buf) * 100 / strlen(buf); | ||||
| 	wmove(win, height - 3, width - 9); | ||||
| 	wmove(win, getmaxy(win) - 3, getmaxx(win) - 9); | ||||
| 	wprintw(win, "(%3d%%)", percent); | ||||
| } | ||||
|  |  | |||
|  | @ -509,6 +509,12 @@ int on_key_esc(WINDOW *win) | |||
| 	return -1; | ||||
| } | ||||
| 
 | ||||
| /* redraw screen in new size */ | ||||
| int on_key_resize(void) | ||||
| { | ||||
| 	dialog_clear(); | ||||
| 	return KEY_RESIZE; | ||||
| } | ||||
| 
 | ||||
| struct dialog_list *item_cur; | ||||
| struct dialog_list item_nil; | ||||
|  |  | |||
|  | @ -44,6 +44,12 @@ int dialog_yesno(const char *title, const char *prompt, int height, int width) | |||
| 	int i, x, y, key = 0, button = 0; | ||||
| 	WINDOW *dialog; | ||||
| 
 | ||||
| do_resize: | ||||
| 	if (getmaxy(stdscr) < (height + 4)) | ||||
| 		return -ERRDISPLAYTOOSMALL; | ||||
| 	if (getmaxx(stdscr) < (width + 4)) | ||||
| 		return -ERRDISPLAYTOOSMALL; | ||||
| 
 | ||||
| 	/* center dialog box on screen */ | ||||
| 	x = (COLS - width) / 2; | ||||
| 	y = (LINES - height) / 2; | ||||
|  | @ -96,6 +102,10 @@ int dialog_yesno(const char *title, const char *prompt, int height, int width) | |||
| 		case KEY_ESC: | ||||
| 			key = on_key_esc(dialog); | ||||
| 			break; | ||||
| 		case KEY_RESIZE: | ||||
| 			delwin(dialog); | ||||
| 			on_key_resize(); | ||||
| 			goto do_resize; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -606,9 +606,8 @@ static void conf(struct menu *menu) | |||
| 		reset_dialog(); | ||||
| 		res = dialog_menu(prompt ? prompt : _("Main Menu"), | ||||
| 				  _(menu_instructions), | ||||
| 				  rows, cols, rows - 10, | ||||
| 				  active_menu, &s_scroll); | ||||
| 		if (res == 1 || res == KEY_ESC) | ||||
| 		if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL) | ||||
| 			break; | ||||
| 		if (!item_activate_selected()) | ||||
| 			continue; | ||||
|  | @ -617,7 +616,10 @@ static void conf(struct menu *menu) | |||
| 
 | ||||
| 		submenu = item_data(); | ||||
| 		active_menu = item_data(); | ||||
| 		sym = submenu->sym; | ||||
| 		if (submenu) | ||||
| 			sym = submenu->sym; | ||||
| 		else | ||||
| 			sym = NULL; | ||||
| 
 | ||||
| 		switch (res) { | ||||
| 		case 0: | ||||
|  | @ -683,7 +685,7 @@ static void conf(struct menu *menu) | |||
| static void show_textbox(const char *title, const char *text, int r, int c) | ||||
| { | ||||
| 	reset_dialog(); | ||||
| 	dialog_textbox(title, text, r ? r : rows, c ? c : cols); | ||||
| 	dialog_textbox(title, text, r, c); | ||||
| } | ||||
| 
 | ||||
| static void show_helptext(const char *title, const char *text) | ||||
|  | @ -756,6 +758,8 @@ static void conf_choice(struct menu *menu) | |||
| 			break; | ||||
| 		case KEY_ESC: | ||||
| 			return; | ||||
| 		case -ERRDISPLAYTOOSMALL: | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Sam Ravnborg
				Sam Ravnborg