/* * Image Editor * ------------ * This program allows the direct editing of * images. Currently it only handles GIF files, * because it is designed as a palette-based * editor. */ #include #include #include #include enum { SCALE = 10, XSIZE = 32, YSIZE = 32 }; typedef struct ImageEditor ImageEditor; struct ImageEditor { App *app; Window *win; /* image editor main window */ Colour bgcolour; /* background colour for the window */ MenuBar *mbar; /* menubar */ Menu *file_menu; MenuItem *new_item; MenuItem *open_item; MenuItem *save_item; MenuItem *line_1; MenuItem *quit_item; Menu *edit_menu; MenuItem *undo_item; MenuItem *line_2; MenuItem *sort_palette; Menu *tool_menu; MenuItem *pencil, *sampler; Control *pixedit; /* the pixel editor */ Control *vert, *horiz; /* scroll bars */ Control *paledit; /* the palette editor */ Control *display; /* real-size display */ Control *pixval; /* colour editor */ Control *transparent; /* check box */ Control *red, *green, *blue; /* fields */ Control *add, *change; /* buttons */ char *filename; /* current file */ Image *prev_img; /* the image before the modification */ Image *img; /* the image being edited */ int size; /* size of one pixel when expanded */ int x, y; /* current x and y of top-left shown */ int xsize, ysize; /* page sizes */ int changed; /* has this image been changed? */ int new_width; /* pixel width of new images */ int new_height; /* pixel height of new images */ int new_depth; /* pixel depth of new images */ Window *new_image_window; /* for setting a new image's size */ Control *new_width_input; /* new image's width input field */ Control *new_height_input; /* new image's height input field */ }; /* * Utilities: */ char * int_to_string(int i) { static char buffer[80]; sprintf(buffer, "%d", i); return buffer; } void reduce_palette(Image *img) { long i, x, y; int old_value, new_value; int new_size; int * translate; Colour *new_cmap; if (! img) return; if (img->depth != 8) return; translate = alloc(256 * sizeof(int)); /* Remove redundant colours: */ for (i=0; i < 256; i++) translate[i] = -1; /* colour unused */ for (y=0; y < img->height; y++) for (x=0; x < img->width; x++) translate[img->data8[y][x]] = 1; /* colour used */ new_size = 0; for (i=0; i < 256; i++) if (translate[i] == 1) translate[i] = new_size++; /* map to this entry */ /* Generate the new colour map: */ new_cmap = alloc(new_size * sizeof(Colour)); for (i=0; i < img->cmap_size; i++) { old_value = i; new_value = translate[i]; if (new_value >= 0) new_cmap[new_value] = img->cmap[old_value]; } /* Change the existing colour map: */ img->cmap_size = new_size; for (i=0; i < new_size; i++) img->cmap[i] = new_cmap[i]; free(new_cmap); /* Translate the pixels to the new colour map: */ for (y=0; y < img->height; y++) for (x=0; x < img->width; x++) img->data8[y][x] = translate[img->data8[y][x]]; /* Clean up: */ free(translate); } /* * Functions: */ ImageEditor *find_image_editor(Control *c) { Window *win = parent_window(c); ImageEditor *editor = get_window_data(win); return editor; } ImageEditor *find_image_editor_from_menu_item(MenuItem *mi) { Window *win = parent_window(mi->parent->parent->ctrl); ImageEditor *editor = get_window_data(win); return editor; } void update_colour_editor(ImageEditor *editor, int entry) { Colour colour; Colour *palette; if (entry >= editor->img->cmap_size) return; palette = editor->img->cmap; colour = palette[entry]; set_control_text(editor->pixval, int_to_string(entry)); if (colour.alpha > 0x7F) check(editor->transparent); else uncheck(editor->transparent); set_control_text(editor->red, int_to_string(colour.red)); set_control_text(editor->green, int_to_string(colour.green)); set_control_text(editor->blue, int_to_string(colour.blue)); draw_control(editor->paledit); } void prepare_for_change(ImageEditor *editor) { Image *img_copy; img_copy = copy_image(editor->img); if (editor->prev_img) del_image(editor->prev_img); editor->prev_img = img_copy; } void image_changed(ImageEditor *editor) { if (editor->changed == 0) { enable_menu_item(editor->undo_item); editor->changed = 1; } } void draw_pixel_block(Graphics *g, Colour colour, Rect r) { set_colour(g, rgb(colour.red, colour.green, colour.blue)); fill_rect(g, r); if ((colour.red==255)&&(colour.green==255)&&(colour.blue==255)) { /* white = draw a grey border */ set_colour(g, LIGHT_GREY); draw_rect(g, r); } if (colour.alpha > 0x7F) { /* transparent = draw a 'T' */ if ((colour.red <= 0x33) && (colour.green <= 0x33) && (colour.blue <= 0x33)) set_colour(g, WHITE); /* white on dark bg */ else set_colour(g, BLACK); /* black on light bg */ draw_line(g, pt(r.x+r.width/2-2,r.y+r.height/2-2), pt(r.x+r.width/2+2,r.y+r.height/2-2)); draw_line(g, pt(r.x+r.width/2,r.y+r.height/2-2), pt(r.x+r.width/2,r.y+r.height/2+2)); } } void redraw_pixedit(Control *pixedit, Graphics *g) { ImageEditor *editor; Image *img; int x, y, width, height; int size; int maxy, maxx; Rect r, pix_rect; byte **pixels; Colour *palette; int palsize; byte pixval; Colour colour; editor = find_image_editor(pixedit); pix_rect = get_control_area(pixedit); img = editor->img; width = img->width; height = img->height; size = editor->size; pixels = img->data8; palette = img->cmap; palsize = img->cmap_size; maxy = editor->ysize; if (maxy > height) maxy = height; maxx = editor->xsize; if (maxx > width) maxx = width; for (y=0; y < maxy; y++) { for (x=0; x < maxx; x++) { pixval = pixels[y+editor->y][x+editor->x]; r = rect(x*size+1,y*size+1,size-1,size-1); if (pixval >= palsize) { /* not in palette! */ set_colour(g, BLACK); draw_line(g, pt(r.x,r.y), pt(r.x+r.width,r.y+r.height)); draw_line(g, pt(r.x,r.y+r.height), pt(r.x+r.width,r.y)); } else { /* correct palette entry */ colour = palette[pixval]; draw_pixel_block(g, colour, r); } } } set_colour(g, BLACK); draw_rect(g, pix_rect); } void handle_pixedit_drag(Control *pixedit, int buttons, Point p) { ImageEditor *editor; Image *img; int x, y, width, height; int size; int maxy, maxx; Rect r; byte **pixels; Colour *palette; int palsize; byte pixval; Colour colour; int index; Graphics *g; editor = find_image_editor(pixedit); img = editor->img; width = img->width; height = img->height; size = editor->size; pixels = img->data8; palette = img->cmap; palsize = img->cmap_size; maxy = editor->ysize; if (maxy > height) maxy = height; maxx = editor->xsize; if (maxx > width) maxx = width; x = (p.x - 1) / editor->size; y = (p.y - 1) / editor->size; if (x >= maxx) return; if (y >= maxy) return; if (x < 0) return; if (y < 0) return; pixval = pixels[y+editor->y][x+editor->x]; r = rect(x*size+1,y*size+1,size-1,size-1); if (menu_item_is_checked(editor->sampler)) { update_colour_editor(editor, pixval); } else if (menu_item_is_checked(editor->pencil)) { if (buttons & LEFT_BUTTON) { /* left button draws with selected colour */ index = atoi(get_control_text(editor->pixval)); } else if (buttons & MIDDLE_BUTTON) { /* middle button is a colour sampler */ update_colour_editor(editor, pixval); return; } else if (buttons & RIGHT_BUTTON) { /* right button draws last colour in palette */ index = palsize - 1; } else index = 0; /* should never happen actually */ if (pixval == index) return; pixval = index; pixels[y+editor->y][x+editor->x] = pixval; /* redraw this pixel */ colour = palette[pixval]; g = get_control_graphics(pixedit); draw_pixel_block(g, colour, r); del_graphics(g); draw_control(editor->display); image_changed(editor); } } void handle_pixedit_click(Control *pixedit, int buttons, Point p) { ImageEditor *editor; editor = find_image_editor(pixedit); prepare_for_change(editor); handle_pixedit_drag(pixedit, buttons, p); } void redraw_display(Control *display, Graphics *g) { ImageEditor *editor; Rect sr, dr; editor = find_image_editor(display); sr = rect(0, 0, editor->img->width, editor->img->height); dr = rect(1, 1, editor->img->width, editor->img->height); draw_image(g, dr, editor->img, sr); set_colour(g, BLACK); draw_rect(g, get_control_area(display)); } void redraw_paledit(Control *paledit, Graphics *g) { ImageEditor *editor; int i, rowsize, palsize, selected, wrong = 0; int height; Colour *palette; Colour colour; Rect r; editor = find_image_editor(paledit); r = get_control_area(paledit); palette = editor->img->cmap; palsize = editor->img->cmap_size; selected = atoi(get_control_text(editor->pixval)); if (selected < 0) selected = 0, wrong = 1; if (selected >= palsize) selected = palsize - 1, wrong = 1; if (wrong) update_colour_editor(editor, selected); rowsize = (r.width - 2) / SCALE; height = (r.height - 2) / SCALE; for (i=0; i < palsize; i++) { colour = palette[i]; r = rect(2+SCALE*(i%rowsize),2+SCALE*(i/rowsize),8,8); draw_pixel_block(g, colour, r); if (i == selected) set_colour(g, BLACK); else set_colour(g, WHITE); draw_rect(g, inset_rect(r,-1)); } set_colour(g, WHITE); for (; i < rowsize * height; i++) { r = rect(2+SCALE*(i%rowsize),2+SCALE*(i/rowsize),8,8); fill_rect(g, inset_rect(r,-1)); } set_colour(g, BLACK); draw_rect(g, get_control_area(paledit)); } void handle_paledit_click(Control *paledit, int buttons, Point p) { ImageEditor *editor; int entry, rowsize, palsize; Colour *palette; Rect r; r = inset_rect(get_control_area(paledit),1); if (! point_in_rect(p,r)) return; p = pt(p.x-r.x,p.y-r.y); rowsize = r.width / SCALE; if (p.x > rowsize*SCALE) return; editor = find_image_editor(paledit); palette = editor->img->cmap; palsize = editor->img->cmap_size; entry = (p.x / SCALE) + (p.y / SCALE) * rowsize; if (entry >= palsize) return; update_colour_editor(editor, entry); } int find_colour_component(Control *which) { int wrong = 0; int value; value = atoi(get_control_text(which)); if (value < 0) value = 0, wrong = 1; if (value > 255) value = 255, wrong = 1; if (wrong) set_control_text(which, int_to_string(value)); return value; } void add_colour(Control *btn) { ImageEditor *editor; int i, t, r, g, b; Image *img; Colour *palette; Colour palette2[256]; int palsize; Colour colour; editor = find_image_editor(btn); img = editor->img; palette = img->cmap; palsize = img->cmap_size; if (palsize == 2<depth) { ask_ok(editor->app, "Error", "Sorry, the palette is full."); return; } for (i=0; i < palsize; i++) palette2[i] = palette[i]; if (is_checked(editor->transparent)) t = 0xFF; else t = 0x00; r = find_colour_component(editor->red); g = find_colour_component(editor->green); b = find_colour_component(editor->blue); colour = argb(t,r,g,b); palette2[palsize] = colour; prepare_for_change(editor); set_image_cmap(img, palsize+1, palette2); draw_control(editor->paledit); draw_control(editor->display); image_changed(editor); } void change_colour(Control *btn) { ImageEditor *editor; int i, t, r, g, b; Image *img; Colour *palette; Colour palette2[256]; int palsize; Colour colour; editor = find_image_editor(btn); img = editor->img; palette = img->cmap; palsize = img->cmap_size; for (i=0; i < palsize; i++) palette2[i] = palette[i]; if (is_checked(editor->transparent)) t = 0xFF; else t = 0x00; r = find_colour_component(editor->red); g = find_colour_component(editor->green); b = find_colour_component(editor->blue); i = atoi(get_control_text(editor->pixval)); if (i < 0) return; if (i >= palsize) return; colour = argb(t,r,g,b); palette2[i] = colour; prepare_for_change(editor); set_image_cmap(img, palsize, palette2); draw_control(editor->paledit); draw_control(editor->pixedit); draw_control(editor->display); image_changed(editor); } void update_scrollbars(ImageEditor *editor) { int max; Rect r = get_control_area(editor->pixedit); editor->ysize = (r.height - 2) / editor->size; if (editor->ysize > editor->img->height) editor->ysize = editor->img->height; max = editor->img->height - editor->ysize; change_scroll_bar(editor->vert, editor->y, max, editor->ysize); editor->xsize = (r.width - 2) / editor->size; if (editor->xsize > editor->img->width) editor->xsize = editor->img->width; max = editor->img->width - editor->xsize; change_scroll_bar(editor->horiz, editor->x, max, editor->xsize); } void update_editor(ImageEditor *editor) { update_scrollbars(editor); redraw_control(editor->pixedit); redraw_control(editor->display); redraw_control(editor->paledit); } void reset_editor(ImageEditor *editor) { editor->x = editor->y = 0; update_colour_editor(editor, 0); update_editor(editor); redraw_window(editor->win); } void move_x(Control *s) { ImageEditor *editor; int value; editor = find_image_editor(s); value = get_control_value(s); if (editor->x != value) { editor->x = value; redraw_control(editor->pixedit); } } void move_y(Control *s) { ImageEditor *editor; int value; editor = find_image_editor(s); value = get_control_value(s); if (editor->y != value) { editor->y = value; redraw_control(editor->pixedit); } } int save_image(ImageEditor *editor, char *filename) { if (! filename) /* cancel */ return 0; if (! write_image(editor->img, filename)) { ask_ok(editor->app, "Error", "That file could not be saved. The file format might not yet be supported."); return 0; } /* change the editor filename */ del_string(editor->filename); editor->filename = copy_string(filename); set_window_title(editor->win, filename); /* change the settings */ editor->changed = 0; disable_menu_item(editor->undo_item); prepare_for_change(editor); return 1; } int open_image(ImageEditor *editor, char *filename) { Image *img; img = read_image(filename, 8); if (! img) { ask_ok(editor->app, "Error", "Unable to load image."); return 0; } /* delete the old image from memory */ if (editor->img) del_image(editor->img); /* change the editor filename */ del_string(editor->filename); editor->filename = copy_string(filename); set_window_title(editor->win, filename); /* change the settings */ editor->img = img; editor->changed = 0; disable_menu_item(editor->undo_item); prepare_for_change(editor); /* resize the display panel */ size_control(editor->display, rect(0,0,img->width+2,img->height+2)); /* redraw the various panels */ reset_editor(editor); return 1; } int make_new_image(ImageEditor *editor) { int x, y, width, height; Image *img; byte **pixels; Colour palette[5]; int palsize = 5; palette[0] = BLACK; palette[1] = WHITE; palette[2] = RED; palette[3] = GREEN; palette[4] = BLUE; width = editor->new_width; height = editor->new_height; img = new_image(width, height, editor->new_depth); if (! img) { ask_ok(editor->app, "Error", "Insufficient memory to create a new image."); return 0; } pixels = img->data8; for (y=0; y < height; y++) for (x=0; x < width; x++) pixels[y][x] = 1; set_image_cmap(img, palsize, palette); /* delete the old image from memory */ if (editor->img) del_image(editor->img); /* change the editor filename */ del_string(editor->filename); editor->filename = copy_string("untitled"); set_window_title(editor->win, editor->filename); /* change the settings */ editor->img = img; editor->changed = 0; disable_menu_item(editor->undo_item); prepare_for_change(editor); /* resize the display panel */ size_control(editor->display, rect(0,0,width+2,height+2)); /* redraw the various panels */ reset_editor(editor); return 1; } int ask_save_changed_image(ImageEditor *editor) { int result; char *savename; /* save existing modified image */ if (editor->changed) { result = ask_yes_no_cancel(editor->app, "Save Changes?", "Image has changed. Save changes?"); if (result == CANCEL) /* cancel */ return CANCEL; if (result == YES) { /* save changes */ savename = ask_file_save(editor->app, "Save Image", "Save", editor->filename); if (! save_image(editor, savename)) return CANCEL; del_string(savename); } } return YES; } void set_image_size(Control *b) { ImageEditor *editor = find_image_editor(b); editor->new_width = abs(atoi(get_control_text(editor->new_width_input))); editor->new_height = abs(atoi(get_control_text(editor->new_height_input))); make_new_image(editor); hide_window(parent_window(b)); } void ask_new_image_size(ImageEditor *editor) { Window *w; Font *f; int h; char buf[30]; if (! editor->new_image_window) { f = find_default_font(editor->app); h = font_height(f) + 5; editor->new_image_window = w = new_window(editor->app, rect(50,50,200,h+h+h+70), "New Image Size", TITLEBAR + MODAL); set_window_data(w, editor); new_label(w, rect(10,10,120,h+10), "Pixel width:", ALIGN_LEFT); new_label(w, rect(10,h+30,120,h+10), "Pixel height:", ALIGN_LEFT); editor->new_width_input = new_field(w, rect(135,10,50,h+10), ""); editor->new_height_input = new_field(w, rect(135,h+30,50,h+10), ""); new_button(w, rect(60,h+h+50,80,h+10), "Okay", set_image_size); } sprintf(buf, "%d", editor->new_width); set_control_text(editor->new_width_input, buf); sprintf(buf, "%d", editor->new_height); set_control_text(editor->new_height_input, buf); show_window(editor->new_image_window); } void ask_new_image(MenuItem *mi) { ImageEditor *editor; editor = find_image_editor_from_menu_item(mi); if (ask_save_changed_image(editor) == CANCEL) return; ask_new_image_size(editor); } void ask_open_image(MenuItem *mi) { char *filename; ImageEditor *editor; editor = find_image_editor_from_menu_item(mi); if (ask_save_changed_image(editor) == CANCEL) return; filename = ask_file_open(editor->app, "Open Image", "Open", ""); if (filename) { open_image(editor, filename); del_string(filename); } } void do_save_image(MenuItem *mi) { char *filename; ImageEditor *editor; editor = find_image_editor_from_menu_item(mi); if (editor->filename) filename = copy_string(editor->filename); else filename = ask_file_save(editor->app, "Save Image", "Save", editor->filename); if (filename) { save_image(editor, filename); del_string(filename); } } void ask_save_image(MenuItem *mi) { char *filename; ImageEditor *editor; editor = find_image_editor_from_menu_item(mi); filename = ask_file_save(editor->app, "Save Image", "Save", editor->filename); if (filename) { save_image(editor, filename); del_string(filename); } } void do_quit_program_window(Window *w) { ImageEditor *editor; editor = get_window_data(w); if (ask_save_changed_image(editor) == CANCEL) return; exit(0); } void do_quit_program(MenuItem *mi) { ImageEditor *editor; editor = find_image_editor_from_menu_item(mi); if (ask_save_changed_image(editor) == CANCEL) return; exit(0); } void use_pencil(MenuItem *mi) { ImageEditor *editor; editor = find_image_editor_from_menu_item(mi); check_menu_item(editor->pencil); uncheck_menu_item(editor->sampler); } void use_sampler(MenuItem *mi) { ImageEditor *editor; editor = find_image_editor_from_menu_item(mi); uncheck_menu_item(editor->pencil); check_menu_item(editor->sampler); } void do_undo(MenuItem *mi) { ImageEditor *editor; Image *new_img; editor = find_image_editor_from_menu_item(mi); if (editor->changed) { new_img = copy_image(editor->prev_img); del_image(editor->img); editor->img = new_img; update_editor(editor); } } void do_reduce_palette(MenuItem *mi) { ImageEditor *editor; editor = find_image_editor_from_menu_item(mi); prepare_for_change(editor); reduce_palette(editor->img); reset_editor(editor); image_changed(editor); } void do_sort_palette(MenuItem *mi) { ImageEditor *editor; editor = find_image_editor_from_menu_item(mi); prepare_for_change(editor); image_sort_palette(editor->img); reset_editor(editor); image_changed(editor); } ImageEditor *create_image_editor(App *app) { ImageEditor *editor; Rect r; Window *w; MenuBar *mb; Menu *m; Font *f; int x, y, h, minw, maxw; editor = alloc(sizeof(ImageEditor)); if (! editor) return editor; editor->app = app; editor->filename = copy_string("Untitled"); editor->x = editor->y = 0; editor->size = SCALE; editor->changed = 0; editor->new_width = 32; editor->new_height = 32; editor->new_depth = 8; editor->bgcolour = LIGHT_GREY; r = rect(50,50,576,450); editor->win = w = new_window(app, r, "Image Editor", STANDARD_WINDOW); set_window_data(w, editor); on_window_close(w, do_quit_program_window); editor->mbar = mb = new_menu_bar(w); y = mb->ctrl->area.height; editor->file_menu = m = new_menu(mb, "File"); editor->new_item = new_menu_item(m, "New...", 'N', ask_new_image); editor->open_item = new_menu_item(m, "Open...", 'O', ask_open_image); editor->save_item = new_menu_item(m, "Save", 'S', do_save_image); editor->save_item = new_menu_item(m, "Save As...", 'A', ask_save_image); editor->line_1 = new_menu_item(m, "-", 0, NULL); editor->quit_item = new_menu_item(m, "Exit", 'Q', do_quit_program); editor->file_menu = m = new_menu(mb, "Edit"); editor->undo_item = new_menu_item(m, "Undo", 'Z', do_undo); disable_menu_item(editor->undo_item); editor->line_2 = new_menu_item(m, "-", 0, NULL); editor->sort_palette = new_menu_item(m, "Reduce Palette", 0, do_reduce_palette); editor->sort_palette = new_menu_item(m, "Sort Palette", 0, do_sort_palette); editor->tool_menu = m = new_menu(mb, "Tools"); editor->pencil = new_menu_item(m, "Pencil", 'P', use_pencil); check_menu_item(editor->pencil); editor->sampler = new_menu_item(m, "Colour Sampler", 'L', use_sampler); r = rect(10,y+10,2+XSIZE*SCALE,2+YSIZE*SCALE); editor->pixedit = new_control(w, r); on_control_redraw(editor->pixedit, redraw_pixedit); on_control_mouse_down(editor->pixedit, handle_pixedit_click); on_control_mouse_drag(editor->pixedit, handle_pixedit_drag); editor->ysize = YSIZE; editor->vert = new_scroll_bar(w, rect(r.x+r.width+2,r.y,16,r.height), 0, YSIZE, move_y); editor->xsize = XSIZE; editor->horiz = new_scroll_bar(w, rect(r.x,r.y+r.height+2,r.width,16), 0, XSIZE, move_x); x = r.x + r.width + 30; f = find_default_font(app); h = font_height(f); maxw = font_width(f, "<>", 9); minw = font_width(f, "456789", 6) + 5; if (maxw < minw + 5) maxw = minw + 5; r = rect(x,r.y,150,h); new_label(w, r, "Colour:", ALIGN_LEFT); r = rect(x,r.y+r.height+5,minw,h+10); editor->pixval = new_field(w, r, "0"); disable(editor->pixval); r.x = r.x + maxw + 5; r.height = r.height + 5; r.width = font_width(f, "Transparent ", 12) + 30; editor->transparent = new_check_box(w, r, "Transparent", NULL); r = rect(x, r.y+r.height+5, maxw, h); new_label(w, r, "Red", ALIGN_LEFT); editor->red = new_field(w, rect(r.x,r.y+h+5,minw,h+10), "0"); app_set_field_allowed_chars(editor->red, "0123456789"); app_set_field_allowed_width(editor->red, 3); r.x = r.x + r.width + 5; new_label(w, r, "Green", ALIGN_LEFT); editor->green = new_field(w, rect(r.x,r.y+h+5,minw,h+10), "0"); app_set_field_allowed_chars(editor->green, "0123456789"); app_set_field_allowed_width(editor->green, 3); r.x = r.x + r.width + 5; new_label(w, r, "Blue", ALIGN_LEFT); editor->blue = new_field(w, rect(r.x,r.y+h+5,minw,h+10), "0"); app_set_field_allowed_chars(editor->blue, "0123456789"); app_set_field_allowed_width(editor->blue, 3); r = rect(x,r.y + r.height + h + 20, 76, h+5); editor->add = new_button(w, r, "Add", add_colour); r.x = r.x + r.width + 10; editor->change = new_button(w, r, "Change", change_colour); r = rect(x,r.y + r.height + 5, 150, h); new_label(w, r, "Palette:", ALIGN_LEFT); r = rect(x,r.y+r.height+5,162,162); editor->paledit = new_control(w, r); on_control_redraw(editor->paledit, redraw_paledit); on_control_mouse_up(editor->paledit, handle_paledit_click); r = rect(x,r.y+r.height+10,66,66); editor->display = new_control(w, r); on_control_redraw(editor->display, redraw_display); set_window_background(editor->win, editor->bgcolour); editor->prev_img = NULL; editor->img = NULL; editor->new_image_window = NULL; if (! make_new_image(editor)) return NULL; update_scrollbars(editor); prepare_for_change(editor); return editor; } void show_image_editor(ImageEditor *editor) { show_window(editor->win); } int main(int argc, char *argv[]) { ImageEditor *editor; App *app; app = new_app(argc, argv); editor = create_image_editor(app); if (argv && argv[1]) open_image(editor, argv[1]); show_image_editor(editor); main_loop(app); return 0; }