Skip to content

Commit 7dce817

Browse files
authored
Update main to 1.7 from dev
Update main to 1.7
2 parents 4fb75e0 + c99dbe4 commit 7dce817

18 files changed

+416
-202
lines changed

README.md

+20-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ When you want to edit the workflow, it's still there, untouched.
1313
The controller gets saved with the workflow, so once you've set it up, it's always there for you.
1414
And if you share the workflow with someone else, they get your controller as well...
1515

16+
## Latest update - v1.7, 14th Feb 2025
17+
18+
- Added workspaces (WIP)
19+
- Image viewers now work with batches
20+
- Better support for some rgthree COMBO features
21+
- Option to hide file types such as .safetensors in loader nodes (main settings)
22+
- Option to specify that a node shouldn't show images in controller (right-click nodeblock title)
23+
1624
## Getting started
1725

1826
The Controller is toggled using a button in the top menu. When the sliders icon is blue, the Controller is active.
@@ -99,8 +107,14 @@ Nodes which include an image also have a pin in the top right corner: ![pin](ima
99107
When this is active (blue, the default) the image will be shown at the full width of the controller.
100108
If you unpin the image, you will find a handle at the bottom right of the image that can be used to resize it (vertically).
101109

110+
Right-clicking the title of a nodeblock brings up options to control which widgets should be shown, and which images (if any) should be shown, in this nodeblock.
111+
102112
## Other things to explore
103113

114+
### Workspaces
115+
116+
WIP - you can save and then reload the setup of your controllers from the dropdown triangle ![screenshot](images/dropdown.png). This may be useful if you use the same workflow in different ways. There are plans to make this feature more useful!
117+
104118
### Batches
105119

106120
![image](images/batch.png)
@@ -155,8 +169,12 @@ but you just need to click the refresh button (top right of the Controller) to b
155169

156170
### Settings
157171

158-
In the main settings menu are a few things you can tweak - hiding control_after_generate, a keyboard shortcut to show or hide the Controller,
159-
and settings to control how you can interact with the sliders.
172+
In the main settings menu are a few things you can tweak such as:
173+
174+
- hiding control_after_generate
175+
- keyboard shortcut to show or hide the Controller
176+
- settings to control how you can interact with the sliders
177+
- option to hide filename extensions
160178

161179
There's also a debug setting that I might ask you to use if you report a problem!
162180

__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
VERSION = "1.6.1"
1+
VERSION = "1.7"
22
WEB_DIRECTORY = "./js"
33

44
NODE_CLASS_MAPPINGS= {}

images/dropdown.png

1.56 KB
Loading

js/constants.js

+2
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,10 @@ export class Texts {
121121
static EDIT_WV = "Edit widget visibility"
122122
static IMAGE_WIDGET_NAME = "image viewer"
123123
static UNCONNECTED = "Unconnected Input"
124+
static EDIT_IMAGE_SETTING = "Images"
124125
static ACCEPT_UPSTREAM = "Show upstream images"
125126
static REJECT_UPSTREAM = "Only show my images"
127+
static NO_IMAGES = "Don't show images"
126128
static STACK_ALWAYS = "Only show active tab"
127129
static STACK_IF_NEEDED = "Show all tabs if space allows"
128130
}

js/controller.css

+51-12
Original file line numberDiff line numberDiff line change
@@ -391,13 +391,35 @@
391391
display:none;
392392
}
393393

394+
395+
.nodeblock_image_grid {
396+
display: grid;
397+
justify-content: center;
398+
align-items: center;
399+
justify-items: center;
400+
align-content: center;
401+
height: 100%;
402+
width: auto;
403+
max-width: 100%;
404+
}
405+
406+
.nodeblock_image_grid_image {
407+
max-width: 100%;
408+
max-height: 100%;
409+
padding: 1px;
410+
}
411+
394412
.nodeblock_image_overlay {
395413
position: absolute;
396-
width: calc(100% - 8px);
397-
left: 4px;
398-
clip: rect(0, 0, 0, 0);
399-
/* clip: shape(top, right, bottom, left); NB 'rect' is the only available option */
414+
pointer-events: none;
415+
height: auto;
416+
}
417+
400418

419+
.overlay.overlay_show_grid {
420+
padding: 2px 4px;
421+
bottom: unset;
422+
top: 2.5em;
401423
}
402424

403425
.nodeblock.minimised .nodeblock_image_panel {
@@ -476,13 +498,24 @@
476498
background: #00000000;
477499
}
478500

501+
.combo_label_wrapper {
502+
position: relative;
503+
padding: 0;
504+
margin: 0;
505+
display: flex
506+
;
507+
width: 100%;
508+
height: 100%;
509+
}
510+
479511
.entry_label.combo {
480-
width: 20%;
481512
background-color: var(--second-back-color);
482513
padding: 4px 0px 4px 4px;
483-
top: 4px;
514+
position: unset;
515+
width: unset;
484516
height: 20px;
485-
left: 4px;
517+
flex-shrink:0;
518+
min-width: 0;
486519
}
487520

488521
.entry_label.value {
@@ -504,16 +537,17 @@
504537
text-align: right;
505538
}
506539
.input.clickabletext {
507-
display: block;
540+
/*display:block;*/
508541
text-align: right;
509-
padding: 4px;
542+
padding: 4px;
510543
font-size: 70%;
511-
width: 80%;
512-
left: 20%;
513-
position: relative;
514544
overflow: clip;
515545
text-wrap-mode: nowrap;
516546
text-overflow: ellipsis;
547+
width: unset;
548+
flex-shrink: 1;
549+
flex-grow: 1;
550+
min-width: 0;
517551
}
518552
select.input {
519553
height: calc(var(--font-size) + 4px)
@@ -648,6 +682,10 @@ textarea.input {
648682
display:none !important;
649683
}
650684

685+
.blank {
686+
color: transparent;
687+
}
688+
651689
i {
652690
cursor: pointer;
653691
}
@@ -669,6 +707,7 @@ i {
669707
padding-bottom: 1px;
670708
bottom: unset;
671709
top: 2.5em;
710+
right: 2em;
672711
}
673712

674713
.overlay_paging_icon {

js/controller.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ function on_setup() {
6262
mouse_change(true)
6363
if (e.button==2) e.target.handle_right_click?.(e)
6464
})
65+
window.addEventListener('click', (e)=>{
66+
mouse_change(true)
67+
if (e.ctrlKey) e.target.handle_right_click?.(e)
68+
})
6569
window.addEventListener('mouseup', (e)=>{
6670
mouse_change(false)
6771
ControllerPanel.handle_mouse_up(e)
@@ -80,7 +84,7 @@ function on_setup() {
8084
})
8185
window.addEventListener('keypress', (e) => {
8286
if (e.target.tagName=="CANVAS" || e.target.tagName=="BODY") {
83-
const keysetting = app.ui.settings.getSettingValue(SettingIds.KEYBOARD_TOGGLE, "C")
87+
const keysetting = app.ui.settings.getSettingValue(SettingIds.KEYBOARD_TOGGLE)
8488
if (keysetting==e.key) {
8589
ControllerPanel.toggle()
8690
e.preventDefault()
@@ -121,7 +125,7 @@ app.registerExtension({
121125
async afterConfigureGraph() {
122126
UpdateController.configuring(false)
123127
try {
124-
ControllerPanel.new_workflow()
128+
ControllerPanel.on_new_workflow()
125129
ImageManager.analyse_graph()
126130
ImageManager.send_all()
127131
send_graph_changed(true)

js/controller_panel.js

+28-30
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { observe_resizables, clear_resize_managers } from "./resize_manager.js";
1010
import { Debug } from "./debug.js";
1111

1212
import { NodeInclusionManager } from "./node_inclusion.js";
13-
import { get_all_setting_indices, getSettingValue, global_settings, new_controller_setting_index, get_settings, delete_settings, initialise_settings, valid_settings } from "./settings.js";
13+
import { get_all_setting_indices, getSettingValue, global_settings, new_controller_setting_index, get_settings, delete_settings, initialise_settings, valid_settings, clear_settings } from "./settings.js";
1414
import { update_node_order, add_missing_nodes } from "./settings.js"
1515
import { SettingIds, Timings, Texts, Pixels } from "./constants.js";
1616
import { FancySlider } from "./input_slider.js";
@@ -218,7 +218,7 @@ export class ControllerPanel extends HTMLDivElement {
218218
this.build_controllerPanel()
219219
}
220220

221-
static new_workflow() {
221+
static on_new_workflow() {
222222
Debug.extended('new_workflow')
223223
Object.keys(ControllerPanel.instances).forEach((k)=>{ControllerPanel.instances[k]._remove()})
224224
ControllerPanel.instances = {}
@@ -284,35 +284,16 @@ export class ControllerPanel extends HTMLDivElement {
284284
ControllerPanel.search_button.addEventListener('click', ()=>{
285285
global_settings.highlight = !global_settings.highlight;
286286
classSet(ControllerPanel.search_button, 'litup', global_settings.highlight)
287-
})
287+
})
288+
289+
ControllerPanel.dropdown_button = create('i', 'pi pi-caret-down controller_menu_button', ControllerPanel.buttons)
290+
ControllerPanel.dropdown_button.addEventListener('click', ControllerPanel.top_context_menu)
291+
288292

289293
const exit_focus_button = document.getElementsByTagName('main')[0].getElementsByTagName('button')[0]
290294
exit_focus_button.addEventListener('click', () => {
291295
UpdateController.make_request('exit focus', 10)
292296
})
293-
/* removed from 1.6, will return in 1.7
294-
ControllerPanel.save_button = create('i', 'pi pi-file-export controller_menu_button', ControllerPanel.buttons)
295-
add_tooltip(ControllerPanel.save_button, 'save controller workspace')
296-
ControllerPanel.save_button.addEventListener('click', ()=>{
297-
download_workspace_as_json(ControllerPanel.instances, "workspace.json")
298-
})
299-
300-
ControllerPanel.load_button = create('i', 'pi pi-file-import controller_menu_button', ControllerPanel.buttons)
301-
add_tooltip(ControllerPanel.load_button, 'load controller workspace')
302-
ControllerPanel.load_button.addEventListener('click', async function() {
303-
await load_workspace((new_instances)=>{
304-
if (new_instances.length>0) {
305-
Object.values(ControllerPanel.instances).forEach((instance)=>{instance.delete_controller()})
306-
new_instances.forEach((instance)=>{
307-
const newcp = ControllerPanel.create_new()
308-
set_settings_for_instance(newcp.settings, instance)
309-
})
310-
global_settings.hidden = false
311-
UpdateController.make_request("loaded workspace")
312-
}
313-
}, (e)=>{Debug.error("Load_button",e)})
314-
})
315-
*/
316297

317298
ControllerPanel.update_buttons()
318299

@@ -321,9 +302,26 @@ export class ControllerPanel extends HTMLDivElement {
321302
}
322303
}
323304

305+
static top_context_menu(e) {
306+
open_context_menu(e, "Workspace", [
307+
{
308+
"title": "Save workspace",
309+
"callback":()=>{
310+
download_workspace_as_json(ControllerPanel.instances, "workspace.json")
311+
}
312+
},
313+
{
314+
"title": "Load workspace",
315+
"callback": async ()=>{
316+
await load_workspace( ControllerPanel.on_new_workflow )
317+
}
318+
}
319+
])
320+
}
321+
324322
static redraw(c) {
325323
if (!valid_settings()) {
326-
ControllerPanel.new_workflow()
324+
ControllerPanel.on_new_workflow()
327325
return
328326
}
329327
if (Object.values(ControllerPanel.instances).length>0 && !document.body.contains(Object.values(ControllerPanel.instances)[0])) {
@@ -633,7 +631,7 @@ export class ControllerPanel extends HTMLDivElement {
633631

634632
_build_controllerPanel() {
635633
classSet(this, 'hidden', global_settings.hidden)
636-
this.style.setProperty('--font-size',`${1.333*getSettingValue(SettingIds.FONT_SIZE, 12)}px`)
634+
this.style.setProperty('--font-size',`${1.333*getSettingValue(SettingIds.FONT_SIZE)}px`)
637635
classSet(this, 'read_only', app.canvas.read_only)
638636
add_missing_nodes(this.settings.node_order)
639637

@@ -695,7 +693,7 @@ export class ControllerPanel extends HTMLDivElement {
695693

696694
this.add_button_actions()
697695

698-
const bars = getSettingValue(SettingIds.SHOW_SCROLLBARS, "thin")
696+
const bars = getSettingValue(SettingIds.SHOW_SCROLLBARS)
699697
classSet(this, "hide_scrollbars", bars == "no")
700698
classSet(this, "small_scrollbars", bars == "thin")
701699

@@ -748,7 +746,7 @@ export class ControllerPanel extends HTMLDivElement {
748746
tab.style.flexShrink = `${nm.length + 2}`
749747
tab.style.flexGrow = `${nm.length + 2}`
750748
tab.style.flexBasis = `${nm.length * 20}px`
751-
tab.style.minWidth = `${getSettingValue(SettingIds.MINIMUM_TAB_WIDTH, 50)}px`
749+
tab.style.minWidth = `${getSettingValue(SettingIds.MINIMUM_TAB_WIDTH)}px`
752750
tab.addEventListener('mouseenter', ()=>{Highlighter.group(nm)})
753751
tab.addEventListener('mouseleave', ()=>{Highlighter.group(null)})
754752
tab.addEventListener('mousedown', (e) => {

js/debug.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export class _Debug {
1212

1313
_log(message, level, repeatok) {
1414
if ((message == this.last_message && !repeatok) ||
15-
level > app.ui.settings.getSettingValue(SettingIds.DEBUG_LEVEL, 1)) return
15+
level > app.ui.settings.getSettingValue(SettingIds.DEBUG_LEVEL)) return
1616
this.last_message = message
1717
console.log(`${VERSION} ${(this.prefix instanceof Function) ? this.prefix() : this.prefix}: (${level}) ${message}`)
1818
}

js/image_manager.js

+15-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { app } from "../../scripts/app.js";
22
import { api } from "../../scripts/api.js";
33
import { Debug } from "./debug.js";
4+
import { Timings } from "./constants.js";
45
import { pim } from "./prompt_id_manager.js";
56

67
export function is_image_upload_node(node) {
@@ -31,7 +32,9 @@ export class ImageManager {
3132
static node_listener_map = {} // map to Set: node_id (listened to) to node_id's (listeners)
3233
static node_urls_map = {} // map to urls: node_id to list[str]
3334
static executing_node = null
34-
static last_preview_node = null
35+
static just_finished = false
36+
static last_preview_node = null
37+
static last_preview_image = null
3538
static node_image_change = (node_id)=>{}
3639

3740
static reset() {
@@ -89,7 +92,7 @@ export class ImageManager {
8992
}
9093

9194
static node_reported_images(node_id, imgs) {
92-
if (ImageManager.executing_node) return
95+
if (ImageManager.executing_node || ImageManager.just_finished) return
9396
const urls = []
9497
imgs.filter((i)=>(i.src && ! i.src.endsWith('undefined'))).forEach((i)=>{urls.push(i.src)})
9598
this._set_urls(node_id, urls, node_id)
@@ -99,16 +102,25 @@ export class ImageManager {
99102
// TODO if (!pim.ours(e)) return
100103
ImageManager.executing_node = e.detail
101104
if (!ImageManager.executing_node) {
105+
ImageManager.just_finished = true
102106
Array.from(app.graph._nodes).filter((node)=>(node.imgs && node.imgs.length>0)).forEach((node)=>{
103107
ImageManager.node_reported_images(node.id, node.imgs)
104108
})
109+
setTimeout(()=>{ImageManager.just_finished = false}, Timings.GENERIC_LONGER_DELAY)
105110
}
111+
106112
}
107113

108114
static on_b_preview(e) {
109115
// TODO if (!pim.ours(e)) return
116+
const blob_url = window.URL.createObjectURL(e.detail)
110117
ImageManager.last_preview_node = ImageManager.executing_node
111-
ImageManager._images_received( ImageManager.executing_node, [window.URL.createObjectURL(e.detail),], "b_preview" )
118+
const i = new Image()
119+
i.onload = ()=>{
120+
ImageManager.last_preview_image = {width: i.width, height: i.height}
121+
}
122+
i.src = blob_url
123+
ImageManager._images_received( ImageManager.executing_node, [blob_url,], "b_preview" )
112124
}
113125

114126
static on_executed(e) {

0 commit comments

Comments
 (0)