* Creates an undo point. * @param {ActionMetadata} options * @param {function=} callback
({ name, icon, use_loose_canvas_changes, soft, assume_saved }, callback)
| 2123 | * @param {function=} callback |
| 2124 | */ |
| 2125 | function undoable({ name, icon, use_loose_canvas_changes, soft, assume_saved }, callback) { |
| 2126 | if (!use_loose_canvas_changes) { |
| 2127 | /* For performance (especially with two finger panning), I'm disabling this safety check that preserves certain document states in the history. |
| 2128 | const current_image_data = main_ctx.getImageData(0, 0, main_canvas.width, main_canvas.height); |
| 2129 | if (!current_history_node.image_data || !image_data_match(current_history_node.image_data, current_image_data, 5)) { |
| 2130 | window.console?.log("Canvas image data changed outside of undoable", current_history_node, "current_history_node.image_data:", current_history_node.image_data, "document's current image data:", current_image_data); |
| 2131 | undoable({name: "Unknown [undoable]", use_loose_canvas_changes: true}, ()=> {}); |
| 2132 | } |
| 2133 | */ |
| 2134 | } |
| 2135 | |
| 2136 | if (!assume_saved) { // flag is used for undoable file reloading on save, for reduction in color depth |
| 2137 | saved = false; |
| 2138 | update_title(); |
| 2139 | } |
| 2140 | |
| 2141 | const before_callback_history_node = current_history_node; |
| 2142 | callback?.(); |
| 2143 | if (current_history_node !== before_callback_history_node) { |
| 2144 | show_error_message(`History node switched during undoable callback for ${name}. This shouldn't happen.`); |
| 2145 | window.console?.log(`History node switched during undoable callback for ${name}, from`, before_callback_history_node, "to", current_history_node); |
| 2146 | } |
| 2147 | |
| 2148 | const image_data = main_ctx.getImageData(0, 0, main_canvas.width, main_canvas.height); |
| 2149 | |
| 2150 | redos.length = 0; |
| 2151 | undos.push(current_history_node); |
| 2152 | |
| 2153 | const new_history_node = make_history_node({ |
| 2154 | image_data, |
| 2155 | selection_image_data: selection && selection.canvas.ctx.getImageData(0, 0, selection.canvas.width, selection.canvas.height), |
| 2156 | selection_x: selection && selection.x, |
| 2157 | selection_y: selection && selection.y, |
| 2158 | textbox_text: textbox && textbox.$editor.val(), |
| 2159 | textbox_x: textbox && textbox.x, |
| 2160 | textbox_y: textbox && textbox.y, |
| 2161 | textbox_width: textbox && textbox.width, |
| 2162 | textbox_height: textbox && textbox.height, |
| 2163 | text_tool_font: JSON.parse(JSON.stringify(text_tool_font)), |
| 2164 | tool_transparent_mode, |
| 2165 | foreground_color: selected_colors.foreground, |
| 2166 | background_color: selected_colors.background, |
| 2167 | ternary_color: selected_colors.ternary, |
| 2168 | parent: current_history_node, |
| 2169 | name, |
| 2170 | icon, |
| 2171 | soft, |
| 2172 | }); |
| 2173 | current_history_node.futures.push(new_history_node); |
| 2174 | current_history_node = new_history_node; |
| 2175 | |
| 2176 | $G.triggerHandler("history-update"); // update history view |
| 2177 | |
| 2178 | $G.triggerHandler("session-update"); // autosave |
| 2179 | } |
| 2180 | /** |
| 2181 | * @param {ActionMetadataUpdate} undoable_meta |
| 2182 | * @param {()=> void} undoable_action |
no test coverage detected