Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 46 additions & 19 deletions .github/workflows/installer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-22.04, ubuntu-24.04, windows-2022, macos-13, macos-14]
os: [ubuntu-22.04, ubuntu-24.04, windows-2022, macos-14]

steps:
- name: Check-out repository
Expand All @@ -31,6 +31,13 @@ jobs:
- name: Upgrade package installer for Python
run: python -m pip install --upgrade pip

- name: Install needed libraries (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xfixes0 libxcb-shape0 libxcb-cursor0
sudo apt-get install libcairo2-dev pkg-config

- name: Install Python dependences
run: |
python -m pip install flit
Expand Down Expand Up @@ -74,11 +81,12 @@ jobs:
run: |
echo "SETUP_EXE_PATH=$(python ${{ env.SCRIPTS_PATH }}/Config.py ${{ env.BRANCH_NAME }} ${{ matrix.os }} setup_exe_path)" >> $GITHUB_ENV

- name: Install needed libraries (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xfixes0 libxcb-shape0 libxcb-cursor0
# - name: Install needed libraries (Linux)
# if: runner.os == 'Linux'
# run: |
# sudo apt-get update
# sudo apt-get install libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xfixes0 libxcb-shape0 libxcb-cursor0
# sudo apt-get install libcairo2-dev pkg-config

# - name: Run app in testmode and quit
# shell: bash
Expand Down Expand Up @@ -106,18 +114,37 @@ jobs:
# ${{ secrets.APPLE_CERT_DATA }} ${{ secrets.APPLE_CERT_PASSWORD }}
# ${{ secrets.APPLE_NOTARY_USER }} ${{ secrets.APPLE_NOTARY_PASSWORD }}

# - name: Sign offline app installer (Windows)
# if: |
# runner.os == 'Windows' && github.event_name == 'push' &&
# (env.BRANCH_NAME == 'master' || env.BRANCH_NAME == 'develop')
# uses: lando/code-sign-action@v2
# with:
# file: ${{ env.SETUP_EXE_PATH }}
# certificate-data: ${{ secrets.WINDOZE_CERT_DATA }}
# certificate-password: ${{ secrets.WINDOZE_CERT_PASSWORD }}
# keylocker-host: ${{ secrets.KEYLOCKER_HOST }}
# keylocker-api-key: ${{ secrets.KEYLOCKER_API_KEY }}
# keylocker-cert-sha1-hash: ${{ secrets.KEYLOCKER_CERT_SHA1_HASH }}
# - name: Install DigiCert Client tools from Github Custom Actions marketplace
# if: |
# runner.os == 'windows' && github.event_name == 'push'
# uses: digicert/ssm-code-signing@v1.0.1

# - name: Set up P12 certificate
# if: |
# runner.os == 'windows' && github.event_name == 'push'
# run: |
# echo "${{ secrets.WINDOWS_CERT_DATA }}" | base64 --decode > /d/Certificate_pkcs12.p12
# shell: bash

# - name: Set keylocker variables
# if: |
# runner.os == 'windows' && github.event_name == 'push'
# id: variables
# run: |
# echo "version=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
# echo "SM_HOST=${{ secrets.KEYLOCKER_HOST }}" >> "$GITHUB_ENV"
# echo "SM_API_KEY=${{ secrets.KEYLOCKER_API_KEY }}" >> "$GITHUB_ENV"
# echo "SM_CLIENT_CERT_FILE=D:\\Certificate_pkcs12.p12" >> "$GITHUB_ENV"
# echo "SM_CLIENT_CERT_PASSWORD=${{ secrets.WINDOWS_CERT_PASSWORD }}" >> "$GITHUB_ENV"
# shell: bash

# - name: Sign the binary using keypair alias
# if: |
# runner.os == 'windows' && github.event_name == 'push' && env.BRANCH_NAME == 'master'
# run: |
# smctl sign --keypair-alias key_911959544 --input ${{ env.SETUP_EXE_PATH }}
# shell: cmd


- name: Create zip archive of offline app installer for distribution
run: >
Expand Down Expand Up @@ -172,7 +199,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-22.04, ubuntu-24.04, windows-2022, macos-13, macos-14]
os: [ubuntu-22.04, ubuntu-24.04, windows-2022, macos-14]

steps:
- name: Check-out repository
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/snapcraft.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:

- name: Get branch names
id: branch-name
uses: tj-actions/branch-names@v6
uses: tj-actions/branch-names@v8

- name: Get snap filename
run: |
Expand Down
12 changes: 9 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Version 1.1.1 (28 May 2025)
# Version 1.2.0 (1 March 2026)

Fixed Apple Silicon installer.
Fixed experimental data file parser.
Added ORSO file parser
Added simple constraints
Added model-model constraints
Enabled multi-sample display
Enabled multi-experiment display
Improved plotting
Enhanced status bar display
Moved SLD plot to main display

16 changes: 16 additions & 0 deletions EasyReflectometryApp/Backends/Mock/Analysis.qml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,18 @@ QtObject {
readonly property string fittingStatus: ''//undefined //'Success'
readonly property bool isFitFinished: true
readonly property bool fittingRunning: false
property bool showFitResultsDialog: false
readonly property bool fitSuccess: true
readonly property string fitErrorMessage: ''
readonly property int fitNumRefinedParams: 3
readonly property real fitChi2: 1.2345
readonly property var fitResults: ({ success: true, nvarys: 3, chi2: 1.2345 })

// Fit failure signal (mirrors Python backend)
signal fitFailed(string message)

// Stop fit signal (mirrors Python backend)
signal stopFit()

// Parameters
property int currentParameterIndex: 0
Expand Down Expand Up @@ -100,4 +112,8 @@ QtObject {
function fittingStartStop() {
console.debug('fittingStartStop')
}
function setShowFitResultsDialog(value) {
showFitResultsDialog = value
console.debug(`setShowFitResultsDialog ${value}`)
}
}
4 changes: 2 additions & 2 deletions EasyReflectometryApp/Backends/Mock/Home.qml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ QtObject {
property bool created: false

readonly property var version: {
'number': '1.1.1',
'date': '28 May 2025',
'number': '1.2.0',
'date': '10 March 2026',
}

readonly property var urls: {
Expand Down
100 changes: 100 additions & 0 deletions EasyReflectometryApp/Backends/Mock/Plotting.qml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,25 @@ QtObject {
property double analysisMinY: -40.
property double analysisMaxY: 40.

property int modelCount: 1

// Plot mode properties
property bool plotRQ4: false
property string yMainAxisTitle: 'R(q)'
property bool xAxisLog: false
property string xAxisType: 'linear'
property bool sldXDataReversed: false
property bool scaleShown: false
property bool bkgShown: false

// Signals for plot mode changes
signal plotModeChanged()
signal axisTypeChanged()
signal sldAxisReversedChanged()
signal referenceLineVisibilityChanged()
signal samplePageDataChanged()
signal samplePageResetAxes()

function setQtChartsSerieRef(value1, value2, value3) {
console.debug(`setQtChartsSerieRef ${value1}, ${value2}, ${value3}`)
}
Expand All @@ -33,4 +52,85 @@ QtObject {
console.debug(`drawCalculatedOnSldChart`)
}

function getSampleDataPointsForModel(index) {
console.debug(`getSampleDataPointsForModel ${index}`)
return []
}

function getSldDataPointsForModel(index) {
console.debug(`getSldDataPointsForModel ${index}`)
return []
}

function getModelColor(index) {
console.debug(`getModelColor ${index}`)
return '#0000FF'
}

// Plot mode toggle functions
function togglePlotRQ4() {
plotRQ4 = !plotRQ4
yMainAxisTitle = plotRQ4 ? 'R(q)×q⁴' : 'R(q)'
plotModeChanged()
}

function toggleXAxisType() {
xAxisLog = !xAxisLog
xAxisType = xAxisLog ? 'log' : 'linear'
axisTypeChanged()
}

function reverseSldXData() {
sldXDataReversed = !sldXDataReversed
sldAxisReversedChanged()
}

function flipScaleShown() {
scaleShown = !scaleShown
referenceLineVisibilityChanged()
}

function flipBkgShown() {
bkgShown = !bkgShown
referenceLineVisibilityChanged()
}

// Reference line data accessors (mock implementation)
function getBackgroundData() {
if (!bkgShown) return []
// Return mock horizontal line at background level
return [
{ 'x': 0.01, 'y': -7.0 },
{ 'x': 0.30, 'y': -7.0 }
]
}

function getScaleData() {
if (!scaleShown) return []
// Return mock horizontal line at scale level (log10(1.0) = 0)
return [
{ 'x': 0.01, 'y': 0.0 },
{ 'x': 0.30, 'y': 0.0 }
]
}

// Analysis-specific reference line data accessors (use sample/calculated x-range)
function getBackgroundDataForAnalysis() {
if (!bkgShown) return []
// Return mock horizontal line at background level using sample x-range
return [
{ 'x': sampleMinX, 'y': -7.0 },
{ 'x': sampleMaxX, 'y': -7.0 }
]
}

function getScaleDataForAnalysis() {
if (!scaleShown) return []
// Return mock horizontal line at scale level using sample x-range
return [
{ 'x': sampleMinX, 'y': 0.0 },
{ 'x': sampleMaxX, 'y': 0.0 }
]
}

}
93 changes: 90 additions & 3 deletions EasyReflectometryApp/Backends/Mock/Sample.qml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ pragma Singleton
import QtQuick

QtObject {
// Signals to match the Python backend
signal constraintsChanged
// MATERIALS
readonly property int currentMaterialIndex: -1

Expand Down Expand Up @@ -271,11 +273,96 @@ QtObject {
'parameter 2',
'parameter 3'
]
readonly property var relationOperators: ['=', '&lt', '&gt']
readonly property var relationOperators: [
{ value: '=', text: '=' },
{ value: '>', text: '≥' },
{ value: '<', text: '≤' }
]
readonly property var arithmicOperators: ['', '*', '/', '+', '-']
readonly property var constraintParametersMetadata: [
{ alias: 'parameter_1', displayName: 'parameter 1', independent: true },
{ alias: 'parameter_2', displayName: 'parameter 2', independent: true },
{ alias: 'parameter_3', displayName: 'parameter 3', independent: true }
]

// Mock constraints data - matches the structured format expected by the UI
property var constraintsList: [
{
dependentName: 'Thickness Layer 1',
expression: 'parameter 2 * 0.5 + 1.5',
rawExpression: 'parameter_2 * 0.5 + 1.5',
relation: '=',
type: 'expression'
},
{
dependentName: 'Roughness Layer 2',
expression: 'parameter 1 / 3.14',
rawExpression: 'parameter_1 / 3.14',
relation: '=',
type: 'expression'
},
{
dependentName: 'SLD Layer 3',
expression: '5.0',
rawExpression: '5.0',
relation: '=',
type: 'static'
}
]

function validateConstraintExpression(dependentIndex, relation, expression) {
if (dependentIndex < 0 || dependentIndex >= parameterNames.length) {
return { valid: false, message: 'Select a dependent parameter first.' }
}
const expr = expression !== undefined && expression !== null ? String(expression).trim() : ''
if (expr.length === 0) {
return { valid: false, message: 'Expression cannot be empty.' }
}
return {
valid: true,
message: '',
preview: expr,
relation: relation,
type: relation === '=' ? 'expression' : (relation === '>' ? 'lower_bound' : 'upper_bound')
}
}

function addConstraint(dependentIndex, relation, expression) {
const validation = validateConstraintExpression(dependentIndex, relation, expression)
if (!validation.valid) {
return { success: false, message: validation.message }
}

const constraint = {
dependentName: parameterNames[dependentIndex] || 'Unknown parameter',
expression: validation.preview,
rawExpression: expression,
relation: relation,
type: validation.type
}

var newConstraints = constraintsList.slice()
newConstraints.push(constraint)
constraintsList = newConstraints
constraintsChanged()

return {
success: true,
message: '',
preview: validation.preview,
relation: relation,
type: validation.type
}
}

function addConstraint(value1, value2, value3, value4, value5) {
console.debug(`addConstraint ${value1} ${value2} ${value3} ${value4} ${value5}`)
function removeConstraintByIndex(index) {
console.debug(`removeConstraintByIndex ${index}`)
if (index >= 0 && index < constraintsList.length) {
var newConstraints = constraintsList.slice() // Create a copy
newConstraints.splice(index, 1)
constraintsList = newConstraints
constraintsChanged()
}
}

// Q Range
Expand Down
Loading