Add comprehensive settings panel with layout management
New Features: - Created settings-schema.json with customizable options: * Zone appearance (border width, colors, opacity) * Show/hide zone numbers * Enable/disable Shift+Drag snapping * Enable/disable keyboard snapping (Super+Ctrl+1-9) * Notification on window snap - Created settings.js with custom UI: * View all saved custom layouts * Delete custom layouts with confirmation dialog * Export layouts to JSON files * Visual list with layout info (name, zone count, ID) * Empty state when no custom layouts exist Extension Integration: - Integrated Settings API into extension.js - Zone overlay now respects user-configured colors and opacity - Border width is customizable - Zone numbers can be toggled on/off - Shift-drag and keyboard snap can be disabled via settings - Optional notifications when windows snap to zones - Settings properly cleaned up on extension destroy UI/UX Improvements: - Professional settings panel accessible from System Settings → Extensions - Layout management without editing JSON files manually - Real-time application of visual settings - Destructive actions (delete) require confirmation - Export functionality for sharing layouts Fixes TODO item #12 - Settings Panel Fixes TODO item #13 - Update Metadata (already done) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
81
extension.js
81
extension.js
@@ -342,6 +342,9 @@ ZoneManager.prototype = {
|
||||
this.draggedWindow = null;
|
||||
this.editor = new ZoneEditor();
|
||||
|
||||
// Initialize settings
|
||||
this.settings = new Settings.ExtensionSettings(this, 'gridsnap@cinnamon-extension');
|
||||
|
||||
// Load layouts (default + saved custom layouts)
|
||||
this._loadLayouts();
|
||||
|
||||
@@ -446,6 +449,11 @@ ZoneManager.prototype = {
|
||||
return false; // Stop polling
|
||||
}
|
||||
|
||||
// Check if shift-drag is enabled
|
||||
if (!this.settings.getValue('enable-shift-drag')) {
|
||||
return true; // Continue polling but don't show overlay
|
||||
}
|
||||
|
||||
let pointerInfo = global.get_pointer();
|
||||
let mods = pointerInfo[2];
|
||||
let shiftPressed = !!(mods & Clutter.ModifierType.SHIFT_MASK);
|
||||
@@ -537,7 +545,17 @@ ZoneManager.prototype = {
|
||||
let y = monitor.height * zone.y;
|
||||
let width = monitor.width * zone.width;
|
||||
let height = monitor.height * zone.height;
|
||||
|
||||
|
||||
// Get settings
|
||||
let borderWidth = this.settings.getValue('zone-border-width');
|
||||
let borderColor = this.settings.getValue('zone-border-color');
|
||||
let fillColor = this.settings.getValue('zone-fill-color');
|
||||
let opacity = this.settings.getValue('zone-opacity');
|
||||
let showNumbers = this.settings.getValue('show-zone-numbers');
|
||||
|
||||
// Adjust fill color opacity
|
||||
let fillColorWithOpacity = fillColor.replace(/[\d.]+\)$/g, (opacity / 100) + ')');
|
||||
|
||||
let actor = new St.Widget({
|
||||
style_class: 'gridsnap-zone',
|
||||
x: x,
|
||||
@@ -545,28 +563,30 @@ ZoneManager.prototype = {
|
||||
width: width,
|
||||
height: height
|
||||
});
|
||||
|
||||
|
||||
actor.set_style(
|
||||
'border: 2px solid rgba(100, 149, 237, 0.8);' +
|
||||
'background-color: rgba(100, 149, 237, 0.2);' +
|
||||
'border: ' + borderWidth + 'px solid ' + borderColor + ';' +
|
||||
'background-color: ' + fillColorWithOpacity + ';' +
|
||||
'border-radius: 4px;'
|
||||
);
|
||||
|
||||
// Add zone number label
|
||||
let label = new St.Label({
|
||||
text: String(index + 1),
|
||||
style_class: 'gridsnap-zone-label',
|
||||
x: 10,
|
||||
y: 10
|
||||
});
|
||||
label.set_style(
|
||||
'color: white;' +
|
||||
'font-size: 24px;' +
|
||||
'font-weight: bold;' +
|
||||
'text-shadow: 2px 2px 4px rgba(0,0,0,0.8);'
|
||||
);
|
||||
actor.add_child(label);
|
||||
|
||||
|
||||
// Add zone number label if enabled
|
||||
if (showNumbers) {
|
||||
let label = new St.Label({
|
||||
text: String(index + 1),
|
||||
style_class: 'gridsnap-zone-label',
|
||||
x: 10,
|
||||
y: 10
|
||||
});
|
||||
label.set_style(
|
||||
'color: white;' +
|
||||
'font-size: 24px;' +
|
||||
'font-weight: bold;' +
|
||||
'text-shadow: 2px 2px 4px rgba(0,0,0,0.8);'
|
||||
);
|
||||
actor.add_child(label);
|
||||
}
|
||||
|
||||
return actor;
|
||||
},
|
||||
|
||||
@@ -606,10 +626,20 @@ ZoneManager.prototype = {
|
||||
|
||||
if (targetZone) {
|
||||
this._moveWindowToZone(window, targetZone, monitor);
|
||||
|
||||
// Show notification if enabled
|
||||
if (this.settings.getValue('notification-on-snap')) {
|
||||
Main.notify('GridSnap', 'Window snapped to zone');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_snapToZone: function(zoneIndex) {
|
||||
// Check if keyboard snap is enabled
|
||||
if (!this.settings.getValue('enable-keyboard-snap')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Snap the focused window to a specific zone
|
||||
let window = global.display.focus_window;
|
||||
if (!window) return;
|
||||
@@ -619,6 +649,11 @@ ZoneManager.prototype = {
|
||||
|
||||
let monitor = Main.layoutManager.primaryMonitor;
|
||||
this._moveWindowToZone(window, layout.zones[zoneIndex], monitor);
|
||||
|
||||
// Show notification if enabled
|
||||
if (this.settings.getValue('notification-on-snap')) {
|
||||
Main.notify('GridSnap', 'Window snapped to zone ' + (zoneIndex + 1));
|
||||
}
|
||||
},
|
||||
|
||||
_moveWindowToZone: function(window, zone, monitor) {
|
||||
@@ -674,6 +709,12 @@ ZoneManager.prototype = {
|
||||
this.editor._cancelEditor();
|
||||
}
|
||||
|
||||
// Clean up settings
|
||||
if (this.settings) {
|
||||
this.settings.finalize();
|
||||
this.settings = null;
|
||||
}
|
||||
|
||||
// Disconnect signals
|
||||
if (this.grabOpBeginId) {
|
||||
global.display.disconnect(this.grabOpBeginId);
|
||||
|
||||
Reference in New Issue
Block a user