/* build stuff necessary for rotate dialogue */ static void rotate_update_dialogue(void) { error err; int w,h; int d; int extent; osbool mask; os_mode mode; int xeig,yeig; os_box box; int cx,cy; int r; /* ensure we have a thumbnail ready */ if (LOCALS.thumbnail == NULL) if (thumbnail_create(LOCALS.image, &GLOBALS.choices.drawable, GLOBALS.choices.rotate.max_thumb, &LOCALS.thumbnail)) return; /* failure */ /* read thumbnail details */ osspriteop_read_sprite_info(osspriteop_USER_AREA, LOCALS.thumbnail, (osspriteop_id) "thumbnail", &w,&h, &mask, &mode); /* convert dimensions to OS units */ read_mode_vars(mode, &xeig, &yeig, NULL); w <<= xeig; h <<= yeig; /* get max dimension */ d = ((w > h) ? w : h) * 362 / 256; /* 1.41421356 is approx 362/256 */ /* enforce a minimum dimension so the buttons don't go outside the * window bounds */ extent = (d < MIN_WIDTH) ? MIN_WIDTH : d; box.x0 = 0; box.y0 = -extent - BUTTON_HEIGHT; box.x1 = extent; box.y1 = 0; window_set_submenu_extent(LOCALS.rotate_w, 15, &box); /* cache values */ LOCALS.rotation = 0; LOCALS.flags = 0; LOCALS.extent = extent; /* the box formed by extent squared may be bigger than required due to * minimum size padding. centre our refresh area in this box. */ cx = extent / 2; cy = -extent / 2; r = d / 2; LOCALS.redraw_area.x0 = cx - r; LOCALS.redraw_area.y0 = cy - r; LOCALS.redraw_area.x1 = cx + r; LOCALS.redraw_area.y1 = cy + r; /* adjust button positions */ shift_buttons(&box); if (LOCALS.trans_tab) { free(LOCALS.trans_tab); LOCALS.trans_tab = NULL; } err = make_trans_tab(LOCALS.thumbnail, (osspriteop_id) "thumbnail", &LOCALS.trans_tab); if (err) goto Failure; if (LOCALS.indicator.trans_tab) { free(LOCALS.indicator.trans_tab); LOCALS.indicator.trans_tab = NULL; } err = make_trans_tab((osspriteop_area *) window_get_sprite_area(), (osspriteop_id) "rt-0", &LOCALS.indicator.trans_tab); if (err) goto Failure; /* must now refresh indicator and thumbnail */ wimp_force_redraw(LOCALS.rotate_w, 0, -extent, extent, 0); return; Failure: thumbnail_destroy(&LOCALS.thumbnail); if (LOCALS.trans_tab) { free(LOCALS.trans_tab); LOCALS.trans_tab = NULL; } if (LOCALS.indicator.trans_tab) { free(LOCALS.indicator.trans_tab); LOCALS.indicator.trans_tab = NULL; } return; }
static bool browser_window_history__redraw_entry(struct history *history, struct history_entry *entry, int x0, int y0, int x1, int y1, int x, int y, bool clip, const struct redraw_context *ctx) { const struct plotter_table *plot = ctx->plot; size_t char_offset; int actual_x; struct history_entry *child; colour c = entry == history->current ? HISTORY_COLOUR_SELECTED : HISTORY_COLOUR_FOREGROUND; int tailsize = 5; int xoffset = x - x0; int yoffset = y - y0; plot_style_t pstyle_history_rect = { .stroke_type = PLOT_OP_TYPE_SOLID, .stroke_colour = c, .stroke_width = entry == history->current ? 3 : 1, }; plot_font_style_t fstyle = *plot_style_font; if (clip) { struct rect rect; rect.x0 = x0 + xoffset; rect.y0 = y0 + yoffset; rect.x1 = x1 + xoffset; rect.y1 = y1 + yoffset; if(!plot->clip(&rect)) return false; } if (!plot->bitmap(entry->x + xoffset, entry->y + yoffset, WIDTH, HEIGHT, entry->bitmap, 0xffffff, 0)) return false; if (!plot->rectangle(entry->x - 1 + xoffset, entry->y - 1 + yoffset, entry->x + xoffset + WIDTH, entry->y + yoffset + HEIGHT, &pstyle_history_rect)) return false; if (!nsfont.font_position_in_string(plot_style_font, entry->page.title, strlen(entry->page.title), WIDTH, &char_offset, &actual_x)) return false; fstyle.background = HISTORY_COLOUR_BACKGROUND; fstyle.foreground = c; fstyle.weight = entry == history->current ? 900 : 400; if (!plot->text(entry->x + xoffset, entry->y + HEIGHT + 12 + yoffset, entry->page.title, char_offset, &fstyle)) return false; for (child = entry->forward; child; child = child->next) { if (!plot->line(entry->x + WIDTH + xoffset, entry->y + HEIGHT / 2 + yoffset, entry->x + WIDTH + tailsize + xoffset, entry->y + HEIGHT / 2 + yoffset, plot_style_stroke_history)) return false; if (!plot->line(entry->x + WIDTH + tailsize + xoffset, entry->y + HEIGHT / 2 + yoffset, child->x - tailsize +xoffset, child->y + HEIGHT / 2 + yoffset, plot_style_stroke_history)) return false; if (!plot->line(child->x - tailsize + xoffset, child->y + HEIGHT / 2 + yoffset, child->x + xoffset, child->y + HEIGHT / 2 + yoffset, plot_style_stroke_history)) return false; if (!browser_window_history__redraw_entry(history, child, x0, y0, x1, y1, x, y, clip, ctx)) return false; } return true; } /** * Find the history entry at a position. * * \param entry entry to search from * \param x coordinate * \param y coordinate * \return an entry if found, 0 if none */ static struct history_entry *browser_window_history__find_position( struct history_entry *entry, int x, int y) { struct history_entry *child; struct history_entry *found; if (!entry) return 0; if (entry->x <= x && x <= entry->x + WIDTH && entry->y <= y && y <= entry->y + HEIGHT) return entry; for (child = entry->forward; child; child = child->next) { found = browser_window_history__find_position(child, x, y); if (found) return found; } return 0; } /** * Enumerate subentries in history * See also history_enumerate() * * \param bw The browser window to enumerate history of * \param entry entry to start enumeration at * \param cb callback function * \param ud context pointer passed to cb * \return true to continue enumeration, false to cancel */ static bool browser_window_history__enumerate_entry( const struct browser_window *bw, const struct history_entry *entry, browser_window_history_enumerate_cb cb, void *ud) { const struct history_entry *child; if (!cb(bw, entry->x, entry->y, entry->x + WIDTH, entry->y + HEIGHT, entry, ud)) return false; for (child = entry->forward; child; child = child->next) { if (!browser_window_history__enumerate_entry(bw, child, cb, ud)) return false; } return true; } /* -------------------------------------------------------------------------- */ /** * Create a new history tree for a browser window window. * * \param bw browser window to create history for. * * \return NSERROR_OK or appropriate error otherwise */ nserror browser_window_history_create(struct browser_window *bw) { struct history *history; bw->history = NULL; history = calloc(1, sizeof *history); if (!history) { warn_user("NoMemory", 0); return NSERROR_NOMEM; } history->width = RIGHT_MARGIN / 2; history->height = BOTTOM_MARGIN / 2; bw->history = history; return NSERROR_OK; } /** * Clone a bw's history tree for new bw * * \param existing browser window with history to clone. * \param clone browser window to make cloned history for. * * \return NSERROR_OK or appropriate error otherwise */ nserror browser_window_history_clone(const struct browser_window *existing, struct browser_window *clone) { struct history *new_history; clone->history = NULL; if (existing == NULL || existing->history == NULL || existing->history->start == NULL) /* Nothing to clone, create new history for clone window */ return browser_window_history_create(clone); /* Make cloned history */ new_history = malloc(sizeof *new_history); if (!new_history) return NSERROR_NOMEM; clone->history = new_history; memcpy(new_history, existing->history, sizeof *new_history); new_history->start = browser_window_history__clone_entry(new_history, new_history->start); if (!new_history->start) { LOG(("Insufficient memory to clone history")); warn_user("NoMemory", 0); browser_window_history_destroy(clone); clone->history = NULL; return NSERROR_NOMEM; } return NSERROR_OK; } /** * Insert a url into the history tree. * * \param bw browser window with history object * \param content content to add to history * \param frag_id fragment identifier, or NULL. * * The page is added after the current entry and becomes current. */ void browser_window_history_add(struct browser_window *bw, struct hlcache_handle *content, lwc_string *frag_id) { struct history *history; struct history_entry *entry; nsurl *nsurl = hlcache_handle_get_url(content); char *title; struct bitmap *bitmap; assert(bw); assert(bw->history); assert(content); history = bw->history; /* allocate space */ entry = malloc(sizeof *entry); if (entry == NULL) return; title = strdup(content_get_title(content)); if (title == NULL) { warn_user("NoMemory", 0); free(entry); return; } entry->page.url = nsurl_ref(nsurl); entry->page.frag_id = frag_id ? lwc_string_ref(frag_id) : 0; entry->page.title = title; entry->back = history->current; entry->next = 0; entry->forward = entry->forward_pref = entry->forward_last = 0; entry->children = 0; entry->bitmap = 0; if (history->current) { if (history->current->forward_last) history->current->forward_last->next = entry; else history->current->forward = entry; history->current->forward_pref = entry; history->current->forward_last = entry; history->current->children++; } else { history->start = entry; } history->current = entry; /* if we have a thumbnail, don't update until the page has finished * loading */ bitmap = urldb_get_thumbnail(nsurl); if (!bitmap) { LOG(("Creating thumbnail for %s", nsurl_access(nsurl))); bitmap = bitmap_create(WIDTH, HEIGHT, BITMAP_NEW | BITMAP_CLEAR_MEMORY | BITMAP_OPAQUE); if (!bitmap) { warn_user("NoMemory", 0); return; } if (thumbnail_create(content, bitmap, nsurl) == false) { /* Thumbnailing failed. Ignore it silently */ bitmap_destroy(bitmap); bitmap = NULL; } } entry->bitmap = bitmap; browser_window_history__layout(history); } /** * Update the thumbnail for the current entry. * * \param history opaque history structure, as returned by history_create() * \param content content for current entry */ void browser_window_history_update(struct browser_window *bw, struct hlcache_handle *content) { struct history *history; char *title; assert(bw != NULL); history = bw->history; if (!history || !history->current || !history->current->bitmap) return; assert(history->current->page.url); assert(history->current->page.title); title = strdup(content_get_title(content)); if (!title) { warn_user("NoMemory", 0); return; } assert(title); free(history->current->page.title); history->current->page.title = title; thumbnail_create(content, history->current->bitmap, NULL); } /** * Free a history structure. * * \param history opaque history structure, as returned by history_create() */ void browser_window_history_destroy(struct browser_window *bw) { assert(bw != NULL); if (bw->history == NULL) return; browser_window_history__free_entry(bw->history->start); free(bw->history); bw->history = NULL; }