def wbuild(config: Dict[str, Dict[str, Any]], win_out_dir: Path, info: Info) -> None: """Build `GoogleDot` cursor theme for only `Windows` platforms. :param config: `GoogleDot` configuration. :type config: ``Dict`` :param win_out_dir: Path to the output directory,\ Where the `Windows` cursor theme package will generate.\ It also creates a directory if not exists. :type win_out_dir: ``pathlib.Path`` :param info: Content theme name & comment. :type info: Info """ for _, item in config.items(): with CursorAlias.from_bitmap(item["png"], item["hotspot"]) as alias: alias.create(item["x_sizes"], item["delay"]) if item.get("win_key"): win_cfg = alias.reproduce( size=item["win_size"], canvas_size=item["canvas_size"], position=item["position"], delay=item["win_delay"], ).rename(item["win_key"]) print(f"Building '{win_cfg.stem}' Windows Cursor...") WindowsCursor.create(win_cfg, win_out_dir) WindowsPackager(win_out_dir, info.name, info.comment, AUTHOR, URL)
def build() -> None: config = get_config() # Building for _, item in config.items(): png = item["png"] hotspot = item["hotspot"] delay = item["delay"] with CursorAlias.from_bitmap(png, hotspot) as alias: x_cfg = alias.create(X_SIZES, delay) XCursor.create(x_cfg, x_out_dir) if item.get("win_key"): win_build(item, alias) theme_name: str = "Example" comment: str = "Example theme generated from clickgen" author: str = "Kaiz Khatri" url: str = "https://github.com/ful1e5/clickgen/tree/main/examples" add_missing_xcursors(x_out_dir / "cursors", rename=True, force=True) XPackager(x_out_dir, theme_name, comment) WindowsPackager(win_out_dir, theme_name, comment, author, url)
def xbuild(config: Dict[str, Dict[str, Any]], x_out_dir: Path, info: Info) -> None: """Build `GoogleDot` cursor theme for only `X11`(UNIX) platform. :param config: `GoogleDot` configuration. :type config: ``Dict`` :param x_out_dir: Path to the output directory,\ Where the `X11` cursor theme package will generate.\ It also creates a directory if not exists. :type x_out_dir: ``pathlib.Path`` :param info: Content theme name & comment. :type info: Info """ for _, item in config.items(): with CursorAlias.from_bitmap(item["png"], item["hotspot"]) as alias: x_cfg = alias.create(item["x_sizes"], item["delay"]) print(f"Building '{x_cfg.stem}' XCursor...") XCursor.create(x_cfg, x_out_dir) add_missing_xcursor(x_out_dir / "cursors") XPackager(x_out_dir, info.name, info.comment)
def test_CursorAlias_from_bitmap(static_png, hotspot) -> None: """Testing CursorAlias ``from_bitmap`` method.""" directory: Path with CursorAlias.from_bitmap(static_png, hotspot) as ca: assert isinstance(ca, CursorAlias) assert ca.bitmap is not None assert ca.alias_dir is not None assert ca.alias_dir.exists() is True assert ca.garbage_dirs == [] directory = ca.alias_dir assert directory.exists() is False or list(directory.iterdir()) == [] with CursorAlias.from_bitmap(static_png, hotspot) as ca1: with pytest.raises(AttributeError) as excinfo: assert ca1.alias_file is not None assert (str(excinfo.value) == "'CursorAlias' object has no attribute 'alias_file'") ca1.create((10, 10)) assert ca1.alias_file is not None
def test_add_missing_xcursors_without_rename_and_force( data, tmpdir_factory: pytest.TempdirFactory) -> None: d = tmpdir_factory.mktemp("ffff") tmp_dir = Path(d) images = create_test_image(tmp_dir, 2, key="fffff0") with CursorAlias.from_bitmap(images, (0, 0)) as alias: config_file = alias.create((10, 10), delay=2) XCursor.create(config_file, tmp_dir) x_dir = tmp_dir / "cursors" add_missing_xcursors(x_dir, data) assert list(map(lambda x: x.name, x_dir.iterdir())) == ["fffff0"] shutil.rmtree(tmp_dir)
def build(config: Dict[str, Dict[str, Any]], x_out_dir: Path, win_out_dir: Path, info: Info) -> None: """Build `Bibata Rainbow` cursor theme for `X11` & `Windows` platforms. :param config: `Bibata` configuration. :type config: Dict[str, Dict[str, Any]] :param win_out_dir: Path to the output directory,\ Where the `Windows` cursor theme package will \ generate. It also creates a directory if not exists. :type win_out_dir: Path :param info: Content theme name & comment :type info: Dict """ def win_build(item: Dict[str, Any], alias: CursorAlias) -> None: position = item["position"] win_size = item["win_size"] win_key = item["win_key"] canvas_size = item["canvas_size"] win_delay = item["win_delay"] win_cfg = alias.reproduce(win_size, canvas_size, position, delay=win_delay).rename(win_key) print(f"Building '{win_cfg.stem}' Windows Cursor...") WindowsCursor.create(win_cfg, win_out_dir) for _, item in config.items(): png = item["png"] hotspot = item["hotspot"] x_sizes = item["x_sizes"] delay = item["delay"] with CursorAlias.from_bitmap(png, hotspot) as alias: x_cfg = alias.create(x_sizes, delay) print(f"Building '{x_cfg.stem}' XCursor...") XCursor.create(x_cfg, x_out_dir) if item.get("win_key"): win_build(item, alias) add_missing_xcursor(x_out_dir / "cursors") XPackager(x_out_dir, info.name, info.comment) WindowsPackager(win_out_dir, info.name, info.comment, AUTHOR, URL)
def test_CursorAlias_reproduce(static_png, hotspot) -> None: """Testing CursorAlias reproduce method with static bitmap.""" testing_dirs: List[Path] with CursorAlias.from_bitmap(static_png, hotspot) as alias: alias.create((10, 10)) assert alias.garbage_dirs == [] reproduced_alias = alias.reproduce(size=(24, 24), canvas_size=(32, 32), delay=44) testing_dirs = alias.garbage_dirs assert f"{alias.prefix}__garbage_bmps__" in alias.garbage_dirs[0].name assert file_tree(reproduced_alias) == [ "32x32", "test-0.alias", "test-0.png" ] assert (sorted( filter(lambda x: x.is_file is True, testing_dirs[0].glob("*/**"))) == [])
def test_add_missing_xcursors_with_rename_and_force( data, tmpdir_factory: pytest.TempdirFactory) -> None: d = tmpdir_factory.mktemp("ffff") tmp_dir = Path(d) images = create_test_image(tmp_dir, 2, key="ffffd") with CursorAlias.from_bitmap(images, (0, 0)) as alias: config_file = alias.create((10, 10), delay=2) XCursor.create(config_file, tmp_dir) x_dir = tmp_dir / "cursors" add_missing_xcursors(x_dir, data, rename=True) with pytest.raises(FileExistsError): add_missing_xcursors(x_dir, data, rename=True) add_missing_xcursors(x_dir, data, rename=True, force=True) assert sorted(list(map(lambda x: x.name, x_dir.iterdir()))) == sorted(["ddddd", "ffffff"]) shutil.rmtree(tmp_dir)
def from_bitmap(cls, **kwargs) -> Path: if "png" not in kwargs: raise KeyError("argument 'png' required") elif "hotspot" not in kwargs: raise KeyError("argument 'hotspot' required") elif "size" not in kwargs: raise KeyError("argument 'size' required") elif "canvas_size" not in kwargs: raise KeyError("argument 'canvas_size' required") elif "out_dir" not in kwargs: raise KeyError("argument 'out_dir' required") position: str if "position" in kwargs: position = kwargs["position"] else: position = "center" options: Options if "options" in kwargs: options = kwargs["options"] else: options = Options() with CursorAlias.from_bitmap(kwargs["png"], kwargs["hotspot"]) as alias: if alias.bitmap.animated: if "delay" not in kwargs: raise KeyError("argument 'delay' required") else: alias.create(kwargs["size"], kwargs["delay"]) alias.reproduce(kwargs["size"], kwargs["canvas_size"], position, kwargs["delay"]) else: alias.create(kwargs["size"]) alias.reproduce(kwargs["size"], kwargs["canvas_size"], position) cursor = cls(alias.alias_file, kwargs["out_dir"], options) cursor.generate() return cursor.out
def test_WindowsCursor_create_with_animated_config(hotspot, image_dir) -> None: """Testing WindowsCursor generate animated (.ani) cursor with ``create`` \ classmethod. """ animated_png = create_test_image(image_dir, 4) with CursorAlias.from_bitmap(animated_png, hotspot) as alias: cfg = alias.create((10, 10), delay=999999999) # Cover more than one delay sets new_lines = [] with cfg.open("r") as f: lines = f.readlines() for l in lines: new_lines.append(l.replace("999999999", str(randint(20, 30)))) with cfg.open("w") as f: f.writelines(new_lines) with WindowsCursor.create(cfg, image_dir) as win: assert win.exists() is True assert win.suffix == ".ani" assert win.__sizeof__() > 0
def from_bitmap(cls, **kwargs) -> Path: if "png" not in kwargs: raise KeyError("argument 'png' required") elif "hotspot" not in kwargs: raise KeyError("argument 'hotspot' required") elif "x_sizes" not in kwargs: raise KeyError("argument 'x_sizes' required") elif "out_dir" not in kwargs: raise KeyError("argument 'out_dir' required") with CursorAlias.from_bitmap(kwargs["png"], kwargs["hotspot"]) as alias: x_cfg: Path if alias.bitmap.animated: if "delay" not in kwargs: raise KeyError("argument 'delay' required") else: x_cfg = alias.create(kwargs["x_sizes"], kwargs["delay"]) else: x_cfg = alias.create(kwargs["x_sizes"]) cursor = cls(x_cfg, kwargs["out_dir"]) cursor.generate() return cursor.out
def main() -> None: parser = argparse.ArgumentParser( prog="clickgen", description="The hassle-free cursor building toolbox", ) # Positional Args. parser.add_argument( "png", metavar="PNG", type=str, nargs="+", help= "Path to .png file. If animated, Try to mask frame-number using asterisk( * ). For Example 'wait-*.png'", ) parser.add_argument( "-o", "--out-dir", dest="out_dir", metavar="OUT", type=str, default="./", help="To change output directory. (default: %(default)s)", ) # Optional Args. parser.add_argument( "-hot", "--hotspot", dest="hotspot", metavar="cord", nargs=2, default=(0, 0), type=int, help= "To set 'x' & 'y' coordinates of cursor's hotspot. (default: %(default)s)", ) parser.add_argument( "-t", "--type", dest="type", choices=("windows", "xcursor", "all"), default="all", help= "Set cursor type, Which you want to build. (default: '%(default)s')", ) parser.add_argument( "-s", "--sizes", dest="sizes", metavar="size", nargs="+", default=[22], type=int, help="Set pixel-size for cursor. (default: %(default)s)", ) parser.add_argument( "-d", "--delay", dest="delay", metavar="ms", default=50, type=int, help= "Set animated cursor's frames delay in 'micro-second'. (default: %(default)s)", ) args = parser.parse_args() hotspot = (args.hotspot[0], args.hotspot[1]) sizes = [(s, s) for s in args.sizes] out_dir = Path(args.out_dir) if not out_dir.exists(): out_dir.mkdir(parents=True, exist_ok=True) with CursorAlias.from_bitmap(args.png, hotspot) as alias: cfg = alias.create(sizes) if args.type == "windows": WindowsCursor.create(cfg, out_dir) elif args.type == "xcursor": # Using Temporary directory, Because 'XCursor' create inside 'cursors' directory. tmp_dir = Path(tempfile.mkdtemp()) try: xcursor = XCursor.create(cfg, tmp_dir) shutil.move(str(xcursor.absolute()), str(out_dir.absolute())) finally: shutil.rmtree(tmp_dir) else: tmp_dir = Path(tempfile.mkdtemp()) try: xcursor = XCursor.create(cfg, tmp_dir) win_cursor = WindowsCursor.create(cfg, tmp_dir) shutil.move(str(xcursor.absolute()), str(out_dir.absolute())) shutil.move(str(win_cursor.absolute()), str(out_dir.absolute())) finally: shutil.rmtree(tmp_dir)