diff --git a/README.md b/README.md
index 068d9f219ff29d1a7f83e87f6c0f9c095aa575e1..3ea34a4a9302dc1d0a2416ec7beb23955f310025 100644
--- a/README.md
+++ b/README.md
@@ -5,8 +5,10 @@ SNLO-Helper helps to use [SNLO](https://as-photonics.com/products/snlo/) softwar
 An autoclicker clicks different buttons and fills fields in order to automate SNLO simulations.
 Afterwards, it can retrieve the results and return them as a dictionary.
 
-Note that the script does use your mouse and keyboard, so you should not interact with the computer at the same time.
-The autoclicker can be interrupted by moving the mouse into the top right corner of the screen.
+Attention:
+- The script does use your mouse and keyboard, so you should not interact with the computer at the same time.
+- The script uses predefined positions of the windows, so **do not move the windows**.
+- The autoclicker can be interrupted by moving the mouse into the top left corner of the screen.
 
 
 ## Installation
@@ -19,10 +21,10 @@ Install it executing `pip install -e .` in this folder or via `pip install git+h
 ### Quick Start
 
 1. Start SNLO on your computer
-2. Import `snlohelper.snlo` as a starting point.
-3. If your screen resolution differs from HD, you have to set screenfactors with `utils.set_screenfactors`.
-   That will rescale all positions to your current screen resolution.
-4. Open the desired method and execute it.
+2. Import `snlohelper.main_window.MainWindow` as a starting point.
+3. Create an instande `mw = MainWindow`
+4. Open the desired function: `ri = mw.open_function(Functions.REF_INDEX)`
+5. Execute it `no, ne = ri.refractive_indices(Wavelength=1234)`
 
 Here is a small snippet how to do a 2D mix of long pulses:
 ```
@@ -42,9 +44,9 @@ For more examples see the `examples` folder.
 
 ### General usage
 
-* The `main_window.open_function` method allows to open any SNLO function of the main window.
+* The `main_window.MainWindow` class manages the main window.
 * For several functions exists a module containing a class, which in turn allows to configure the function, to run the calculation, and to extract the result.
-  1. You start that class, for example `mix = two_d_mix_lp.TwoDMixLp()`.
+  1. You start that class, for example `mix = two_d_mix_lp.TwoDMixLp()` or `mix = MainWindow().open_function("2D-Mix-LP")`.
   2. You can configure it giving a configuration dictionary (the keys correspond to the names) with `mix.configure({"Wavelengths": [1064, None, None]})`
   3. You can run it with `mix.run()`
   4. With `results = mix.read_results()` you can extract the resulting text.
diff --git a/snlohelper/base_function.py b/snlohelper/base_function.py
index 8c38479128ca96bd6c8ff6b4889ff24946caac9e..0e55cc4e31edc2369fa896f2cbf6e7b3b636894b 100644
--- a/snlohelper/base_function.py
+++ b/snlohelper/base_function.py
@@ -2,7 +2,7 @@ import time
 from typing import Any, Optional, Protocol
 
 from .utils import Point, gui, scale, get_content_complete, set_value
-from .main_window import Functions, open_function
+from .functions import Functions, open_function
 
 
 class BaseFunction(Protocol):
diff --git a/snlohelper/focus.py b/snlohelper/focus.py
index 53f8826f4c325ad43bfe992cfb394d9d8b88d74a..f4deaacb003db07ddb26179cc90f1505ccd1c2ee 100644
--- a/snlohelper/focus.py
+++ b/snlohelper/focus.py
@@ -1,4 +1,7 @@
-from .main_window import open_function, Functions
+from typing import Optional
+
+from .base_function import BaseFunction
+from .functions import open_function, Functions
 from .utils import Point, gui, scale, set_value, get_value_complete
 
 
@@ -41,3 +44,37 @@ def focus(
     radcurv = get_value_complete(_dict_focus["Radius of curv. (mm)"])
     angle = get_value_complete(_dict_focus["Far field ang air (mrad)"])
     return zr, diameter, radcurv, angle
+
+
+class Focus(BaseFunction):
+    _function = Functions.FOCUS
+
+    def __init__(self) -> None:
+        super().__init__()
+        self._configuration_pos = {key: [value] for key, value in _dict_focus.items()}
+
+    def read_results(self) -> list[str]:
+        return super().read_results()
+
+    def focus(
+        self,
+        wavelength_nm: Optional[float] = None,
+        ref_index: Optional[float] = None,
+        fwhm_mm: Optional[float] = None,
+        focus_pos_mm: Optional[float] = None,
+    ) -> tuple[float, float, float, float]:
+        self.configure(
+            {
+                "Wavelength (nm)": wavelength_nm,
+                "Refractive Index": ref_index,
+                "Waist size (mm)": fwhm_mm,
+                # Set face to focus and dist to focus to same value gives values in air at face
+                "Face to focus (mm)": focus_pos_mm,
+                "Dist. to focus (mm)": focus_pos_mm,
+            }
+        )
+        zr = get_value_complete(_dict_focus["Rayleigh z in xtal (mm)"])
+        diameter = get_value_complete(_dict_focus["Beam size (mm)"])
+        radcurv = get_value_complete(_dict_focus["Radius of curv. (mm)"])
+        angle = get_value_complete(_dict_focus["Far field ang air (mrad)"])
+        return zr, diameter, radcurv, angle
diff --git a/snlohelper/functions.py b/snlohelper/functions.py
new file mode 100644
index 0000000000000000000000000000000000000000..ae7c0144bfe7840f10d0c32970ab5a605c5d1042
--- /dev/null
+++ b/snlohelper/functions.py
@@ -0,0 +1,53 @@
+from enum import StrEnum
+
+from .utils import Point, gui, scale
+
+
+# coordinates of the functions (in FHD standard)
+_functions_coord: dict[str, Point] = {
+    "Ref. Ind.": (66, 46),
+    "Qmix": (66, 66),
+    "Bmix": (66, 93),
+    "QPM": (66, 120),
+    "Opoangles": (66, 146),
+    "Ncpm": (66, 173),
+    "GVM": (66, 200),
+    "PW-mix-LP": (66, 233),
+    "PW-mix-SP": (66, 260),
+    "PW-mix-BB": (66, 286),
+    "2D-mix-LP": (66, 313),
+    "2D-mix-SP": (66, 340),
+    "PW-cav-LP": (66, 366),
+    "PW-OPO-SP": (66, 393),
+    "PW-OPO-BB": (66, 420),
+    "2D-cav-LP": (66, 446),
+    "Focus": (66, 473),
+    "Cavity": (66, 500),
+}
+
+
+class Functions(StrEnum):
+    """Enum for the functions."""
+
+    REF_INDEX = "Ref. Ind."
+    QMIX = "Qmix"
+    BMIX = "Bmix"
+    QPM = "QPM"
+    OPO_ANGLES = "Opoangles"
+    NCPM = "Ncpm"
+    GVM = "GVM"
+    PW_MIX_LP = "PW-mix-LP"
+    PW_MIX_SP = "PW-mix-SP"
+    PW_MIX_BB = "PW-mix-BB"
+    TWOD_MIX_LP = "2D-mix-LP"
+    TWOD_MIX_SP = "2D-mix-SP"
+    PW_CAV_LP = "PW-cav-LP"
+    PW_OPO_SP = "PW-OPO-SP"
+    PW_OPO_BB = "PW-OPO-BB"
+    TWOD_CAV_LP = "2D-cav-LP"
+    FOCUS = "Focus"
+    CAVITY = "Cavity"
+
+def open_function(key: str | Functions) -> None:
+    """opens function according to key"""
+    gui.click(*scale(*_functions_coord[key]))
diff --git a/snlohelper/main_window.py b/snlohelper/main_window.py
index 8a79ccdb017134a6ec8e7690ba4361d038cc5bf9..e5b40825db5d88023aad4c9cede8dac80d7f63f9 100644
--- a/snlohelper/main_window.py
+++ b/snlohelper/main_window.py
@@ -2,60 +2,38 @@
 The SNLO main window
 """
 
-from enum import StrEnum
-
-from .utils import Point, gui, scale
-
-# coordinates of the functions (in FHD standard)
-_functions_coord: dict[str, Point] = {
-    "Ref. Ind.": (66, 46),
-    "Qmix": (66, 66),
-    "Bmix": (66, 93),
-    "QPM": (66, 120),
-    "Opoangles": (66, 146),
-    "Ncpm": (66, 173),
-    "GVM": (66, 200),
-    "PW-mix-LP": (66, 233),
-    "PW-mix-SP": (66, 260),
-    "PW-mix-BB": (66, 286),
-    "2D-mix-LP": (66, 313),
-    "2D-mix-SP": (66, 340),
-    "PW-cav-LP": (66, 366),
-    "PW-OPO-SP": (66, 393),
-    "PW-OPO-BB": (66, 420),
-    "2D-cav-LP": (66, 446),
-    "Focus": (66, 473),
-    "Cavity": (66, 500),
+from typing import Optional
+
+from .utils import gui, scale, get_screenfactors, set_screenfactors, Point
+from .functions import Functions, open_function
+from .base_function import BaseFunction
+from .ref_index import RefractiveIndex
+from .focus import Focus
+from .two_d_mix_lp import TwoDMixLP
+from .two_d_mix_sp import TwoDMixSP
+
+
+function_classes = {
+    Functions.REF_INDEX: RefractiveIndex,
+    Functions.TWOD_MIX_LP: TwoDMixLP,
+    Functions.TWOD_MIX_SP: TwoDMixSP,
+    Functions.FOCUS: Focus,
 }
 
 
-class Functions(StrEnum):
-    """Enum for the functions."""
-
-    REF_INDEX = "Ref. Ind."
-    QMIX = "Qmix"
-    BMIX = "Bmix"
-    QPM = "QPM"
-    OPO_ANGLES = "Opoangles"
-    NCPM = "Ncpm"
-    GVM = "GVM"
-    PW_MIX_LP = "PW-mix-LP"
-    PW_MIX_SP = "PW-mix-SP"
-    PW_MIX_BB = "PW-mix-BB"
-    TWOD_MIX_LP = "2D-mix-LP"
-    TWOD_MIX_SP = "2D-mix-SP"
-    PW_CAV_LP = "PW-cav-LP"
-    PW_OPO_SP = "PW-OPO-SP"
-    PW_OPO_BB = "PW-OPO-BB"
-    TWOD_CAV_LP = "2D-cav-LP"
-    FOCUS = "Focus"
-    CAVITY = "Cavity"
-
-
-def open_function(key: str | Functions) -> None:
-    """opens function according to key"""
-    gui.click(*scale(*_functions_coord[key]))
-
-
-def close_snlo() -> None:
-    gui.click(*scale(95, 14))
+class MainWindow:
+    _close_pos = (95, 14)
+
+    def __init__(self, screenfactors: Optional[Point] = None, **kwargs) -> None:
+        super().__init__(**kwargs)
+        sf = get_screenfactors()
+        if sf is None or screenfactors is not None:
+            set_screenfactors(new_factors=screenfactors)
+
+    def close(self) -> None:
+        gui.click(*scale(self._close_pos))
+
+    def open_function(self, key: str | Functions) -> Optional[BaseFunction]:
+        open_function(key)
+        if key in function_classes:
+            return function_classes[key]()
diff --git a/snlohelper/ref_index.py b/snlohelper/ref_index.py
index 6432588abf483e4723ffa7ede8e27c45bfe1134c..07476dec246bf17a69f5c8dbe55a88fd9f2b941b 100644
--- a/snlohelper/ref_index.py
+++ b/snlohelper/ref_index.py
@@ -28,6 +28,12 @@ class RefractiveIndex(BaseFunction):
     def refractive_indices(
         self, Crystal=None, Temperature=None, theta=None, phi=None, Wavelength=None
     ) -> list[float]:
+        """Get the refractive indices (o, e).
+
+        For the crystal, you have to use letters to press, for example "BB" to select the second
+        crystal starting with a "B". In order to ensure, that it starts correctly, use any other
+        letter first, e.g. "ABB".
+        """
         kwargs = {
             "Crystal": Crystal,
             "Temperature": Temperature,
diff --git a/snlohelper/utils.py b/snlohelper/utils.py
index a409c47f6e09c4c240867514040604f74f3e640c..e48775c5cee442e9c1df667b28d0fe98209cf9ec 100644
--- a/snlohelper/utils.py
+++ b/snlohelper/utils.py
@@ -28,8 +28,8 @@ screen resolution.
 """
 
 
-def get_screenfactors(standard: Point = (1920, 1080)) -> Point:
-    """Get the scaling factor from Full HD to the current display resolution."""
+def read_display_screenfactors(standard: Point = (1920, 1080)) -> Point:
+    """Read the scaling factor from Full HD to the current display resolution."""
     width, height = gui.size()
     return standard[0] / width, standard[1] / height
 
@@ -37,11 +37,20 @@ def get_screenfactors(standard: Point = (1920, 1080)) -> Point:
 def set_screenfactors(new_factors: Optional[tuple[float, float]] = None) -> tuple[float, float]:
     """Set the screenfactors to `new_factors` or detect them automatically."""
     global factors
-    factors = get_screenfactors() if new_factors is None else new_factors
+    factors = read_display_screenfactors() if new_factors is None else new_factors
     return factors
 
 
-def scale(x: float | Point, y: float | None = None) -> Point:
+def get_screenfactors() -> Optional[tuple[float, float]]:
+    """Get the current screenfactors or None, if not yet set."""
+    global factors
+    try:
+        return factors
+    except NameError:
+        return None
+
+
+def scale(x: Union[float, Point], y: Optional[float] = None) -> Point:
     """Scale coordinates from the definition standard to the current screen."""
     global factors
     if isinstance(x, (list, tuple)):
@@ -110,3 +119,11 @@ def set_value(position: Point, value: Any) -> None:
     gui.press("delete")
     gui.doubleClick()
     gui.write(str(value))
+
+
+def alt_tab() -> None:
+    gui.hotkey("alt", "tab")
+
+
+def get_position() -> Point:
+    return gui.position()