├── .clang-format ├── .github └── workflows │ └── c.yml ├── .gitignore ├── LICENSE ├── README.md ├── contrib └── systemd │ ├── sov.service │ └── sov.socket ├── meson.build ├── res └── html │ ├── main.css │ └── main.html ├── screenshot.png ├── src ├── kinetic_ui │ ├── egl │ │ ├── ku_gl.c │ │ ├── ku_gl_atlas.c │ │ ├── ku_gl_floatbuffer.c │ │ └── ku_gl_shader.c │ ├── handler │ │ ├── vh_anim.c │ │ ├── vh_button.c │ │ ├── vh_cv_body.c │ │ ├── vh_cv_evnt.c │ │ ├── vh_cv_scrl.c │ │ ├── vh_drag.c │ │ ├── vh_key.c │ │ ├── vh_knob.c │ │ ├── vh_roll.c │ │ ├── vh_slider.c │ │ ├── vh_table.c │ │ ├── vh_tbl_body.c │ │ ├── vh_tbl_evnt.c │ │ ├── vh_tbl_head.c │ │ ├── vh_tbl_scrl.c │ │ ├── vh_textinput.c │ │ └── vh_touch.c │ ├── ku_bitmap.c │ ├── ku_connector_wayland.c │ ├── ku_css.c │ ├── ku_draw.c │ ├── ku_event.c │ ├── ku_fontconfig.c │ ├── ku_gen_css.c │ ├── ku_gen_html.c │ ├── ku_gen_textstyle.c │ ├── ku_gen_type.c │ ├── ku_html.c │ ├── ku_png.c │ ├── ku_recorder.c │ ├── ku_rect.c │ ├── ku_renderer_egl.c │ ├── ku_renderer_soft.c │ ├── ku_text.c │ ├── ku_view.c │ ├── ku_window.c │ └── texture │ │ ├── tg_css.c │ │ ├── tg_knob.c │ │ ├── tg_scaledimg.c │ │ └── tg_text.c ├── mt_core │ ├── mt_channel.c │ ├── mt_log.c │ ├── mt_map.c │ ├── mt_memory.c │ ├── mt_number.c │ ├── mt_path.c │ ├── mt_string.c │ ├── mt_time.c │ ├── mt_vector.c │ ├── mt_wrapper.c │ └── utf8.h ├── mt_core_ext │ ├── ku_bitmap_ext.c │ ├── mt_map_ext.c │ └── mt_string_ext.c ├── mt_core_test │ ├── mt_channel_test.c │ ├── mt_core_test.c │ ├── mt_map_test.c │ ├── mt_memory_test.c │ ├── mt_path_test.c │ ├── mt_string_test.c │ └── mt_vector_test.c ├── mt_math │ ├── mt_math_2d.c │ ├── mt_math_3d.c │ ├── mt_matrix_3d.c │ ├── mt_matrix_4d.c │ ├── mt_vector_2d.c │ ├── mt_vector_3d.c │ └── mt_vector_4d.c ├── mt_math_test │ └── mt_math_2d_test.c └── sov │ ├── draw.c │ ├── gen.c │ ├── jsmn.c │ ├── json.c │ ├── ku_bitmap_ext.c │ ├── sov.c │ └── tree.c ├── tst ├── a_tree.json ├── a_workspace.json ├── b_tree.json ├── b_workspace.json ├── empty_6_tree.json ├── empty_6_workspace.json ├── empty_tree.json ├── empty_workspace.json ├── feh_tree.json ├── feh_workspace.json ├── floating_tree.json ├── floating_workspace.json ├── master │ ├── a_result_a.bmp │ ├── a_result_b.bmp │ ├── b_result_a.bmp │ ├── b_result_b.bmp │ ├── empty_6_result_a.bmp │ ├── empty_6_result_b.bmp │ ├── empty_result_a.bmp │ ├── empty_result_b.bmp │ ├── feh_result_a.bmp │ ├── feh_result_b.bmp │ ├── floating_result_a.bmp │ ├── floating_result_b.bmp │ ├── rotated_result_a.bmp │ └── rotated_result_b.bmp ├── rotated_tree.json ├── rotated_workspace.json ├── runtests.sh ├── stylea │ └── html │ │ ├── main.css │ │ └── main.html └── styleb │ └── html │ ├── main.css │ └── main.html └── wlr-layer-shell-unstable-v1.xml /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: AlwaysBreak 6 | AlignConsecutiveAssignments: true 7 | AlignConsecutiveDeclarations: true 8 | AlignEscapedNewlines: Right 9 | AlignOperands: true 10 | AlignTrailingComments: true 11 | AllowAllParametersOfDeclarationOnNextLine: true 12 | AllowShortBlocksOnASingleLine: true 13 | AllowShortCaseLabelsOnASingleLine: true 14 | AllowShortFunctionsOnASingleLine: false 15 | AllowShortIfStatementsOnASingleLine: true 16 | AllowShortLoopsOnASingleLine: true 17 | AlwaysBreakAfterDefinitionReturnType: None 18 | AlwaysBreakAfterReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: true 20 | AlwaysBreakTemplateDeclarations: MultiLine 21 | BinPackArguments: false 22 | BinPackParameters: false 23 | BraceWrapping: 24 | AfterClass: false 25 | AfterControlStatement: false 26 | AfterEnum: false 27 | AfterFunction: true 28 | AfterNamespace: false 29 | AfterObjCDeclaration: false 30 | AfterStruct: false 31 | AfterUnion: false 32 | AfterExternBlock: false 33 | BeforeCatch: false 34 | BeforeElse: false 35 | IndentBraces: false 36 | SplitEmptyFunction: true 37 | SplitEmptyRecord: true 38 | SplitEmptyNamespace: true 39 | BreakBeforeBinaryOperators: None 40 | BreakBeforeBraces: Allman 41 | BreakBeforeInheritanceComma: false 42 | BreakInheritanceList: BeforeColon 43 | BreakBeforeTernaryOperators: true 44 | BreakConstructorInitializersBeforeComma: false 45 | BreakConstructorInitializers: BeforeColon 46 | BreakAfterJavaFieldAnnotations: false 47 | BreakStringLiterals: true 48 | ColumnLimit: 0 49 | CommentPragmas: '^ IWYU pragma:' 50 | CompactNamespaces: false 51 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 52 | ConstructorInitializerIndentWidth: 4 53 | ContinuationIndentWidth: 4 54 | Cpp11BracedListStyle: true 55 | DerivePointerAlignment: false 56 | DisableFormat: false 57 | ExperimentalAutoDetectBinPacking: false 58 | FixNamespaceComments: true 59 | ForEachMacros: 60 | - foreach 61 | - Q_FOREACH 62 | - BOOST_FOREACH 63 | IncludeBlocks: Preserve 64 | IncludeCategories: 65 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 66 | Priority: 3 67 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 68 | Priority: 2 69 | - Regex: '.*' 70 | Priority: 1 71 | IncludeIsMainRegex: '(Test)?$' 72 | IndentCaseLabels: true 73 | IndentPPDirectives: BeforeHash 74 | IndentWidth: 4 75 | IndentWrappedFunctionNames: false 76 | JavaScriptQuotes: Leave 77 | JavaScriptWrapImports: true 78 | KeepEmptyLinesAtTheStartOfBlocks: true 79 | MacroBlockBegin: '' 80 | MacroBlockEnd: '' 81 | MaxEmptyLinesToKeep: 1 82 | NamespaceIndentation: None 83 | ObjCBinPackProtocolList: Auto 84 | ObjCBlockIndentWidth: 2 85 | ObjCSpaceAfterProperty: false 86 | ObjCSpaceBeforeProtocolList: true 87 | PenaltyBreakAssignment: 2 88 | PenaltyBreakBeforeFirstCallParameter: 19 89 | PenaltyBreakComment: 300 90 | PenaltyBreakFirstLessLess: 120 91 | PenaltyBreakString: 1000 92 | PenaltyBreakTemplateDeclaration: 10 93 | PenaltyExcessCharacter: 1000000 94 | PenaltyReturnTypeOnItsOwnLine: 60 95 | PointerAlignment: Left 96 | ReflowComments: true 97 | SortIncludes: true 98 | SortUsingDeclarations: true 99 | SpaceAfterCStyleCast: true 100 | SpaceAfterTemplateKeyword: true 101 | SpaceBeforeAssignmentOperators: true 102 | SpaceBeforeCpp11BracedList: false 103 | SpaceBeforeCtorInitializerColon: true 104 | SpaceBeforeInheritanceColon: true 105 | SpaceBeforeParens: ControlStatements 106 | SpaceBeforeRangeBasedForLoopColon: true 107 | SpaceInEmptyParentheses: false 108 | SpacesBeforeTrailingComments: 1 109 | SpacesInAngles: false 110 | SpacesInContainerLiterals: true 111 | SpacesInCStyleCastParentheses: false 112 | SpacesInParentheses: false 113 | SpacesInSquareBrackets: false 114 | Standard: Cpp11 115 | StatementMacros: 116 | - Q_UNUSED 117 | - QT_REQUIRE_VERSION 118 | TabWidth: 8 119 | UseTab: ForContinuationAndIndentation 120 | ... 121 | 122 | -------------------------------------------------------------------------------- /.github/workflows/c.yml: -------------------------------------------------------------------------------- 1 | name: C CI 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: prepare deps 17 | run: sudo apt install -y meson ninja-build pkg-config libpng-dev libfreetype-dev libgl-dev libegl-dev libglew-dev libwayland-dev libxkbcommon-dev wayland-protocols libgles2-mesa-dev 18 | - name: configure 19 | run: meson setup build --buildtype=debug -Db_sanitize=address -Db_lundef=false 20 | - name: make 21 | run: ninja -C build 22 | - name: make check 23 | run: cd build && meson test 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | 54 | # Clang cache 55 | .cache/ 56 | -------------------------------------------------------------------------------- /contrib/systemd/sov.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=An overlay that shows schemas for all workspaces to make navigation in sway easier 3 | PartOf=graphical-session.target 4 | After=graphical-session.target 5 | ConditionEnvironment=WAYLAND_DISPLAY 6 | 7 | [Service] 8 | StandardInput=socket 9 | ExecStart=/usr/bin/sov 10 | 11 | [Install] 12 | WantedBy=graphical-session.target -------------------------------------------------------------------------------- /contrib/systemd/sov.socket: -------------------------------------------------------------------------------- 1 | [Socket] 2 | ListenFIFO=%t/sov.sock 3 | SocketMode=0600 4 | 5 | [Install] 6 | WantedBy=sockets.target -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project( 2 | 'sov', 3 | 'c', 4 | version: '0.94', 5 | license: 'MIT', 6 | default_options: ['c_std=gnu99', 7 | 'warning_level=3'] 8 | ) 9 | 10 | cc = meson.get_compiler('c') 11 | 12 | egl = dependency('egl') 13 | png = dependency('libpng') 14 | math = cc.find_library('m') 15 | wegl = dependency('wayland-egl') 16 | glesv2 = dependency('glesv2') 17 | freetype = dependency('freetype2') 18 | xkbcommon = dependency('xkbcommon') 19 | 20 | wayland_client = dependency('wayland-client',version : '>=1.21.0') 21 | wayland_cursor = dependency('wayland-cursor') 22 | wayland_protos = dependency('wayland-protocols') 23 | wayland_scanner_dep = dependency('wayland-scanner') 24 | wayland_scanner = find_program( 25 | wayland_scanner_dep.get_pkgconfig_variable('wayland_scanner') 26 | ) 27 | 28 | wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir') 29 | 30 | protocols = [ 31 | [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], 32 | [wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'], 33 | [wl_protocol_dir, 'unstable/pointer-gestures/pointer-gestures-unstable-v1.xml'], 34 | 'wlr-layer-shell-unstable-v1.xml' 35 | ] 36 | 37 | protos_src = [] 38 | protos_headers = [] 39 | 40 | foreach p : protocols 41 | xml = join_paths(p) 42 | protos_src += custom_target( 43 | xml.underscorify() + '_client_c', 44 | input: xml, 45 | output: '@BASENAME@-protocol.c', 46 | command: [wayland_scanner, 'public-code', '@INPUT@', '@OUTPUT@'], 47 | ) 48 | protos_headers += custom_target( 49 | xml.underscorify() + '_client_h', 50 | input: xml, 51 | output: '@BASENAME@-client-protocol.h', 52 | command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@'], 53 | ) 54 | endforeach 55 | 56 | 57 | sov_dependencies = [wayland_client, 58 | wayland_cursor, 59 | png, 60 | freetype, 61 | math, 62 | glesv2, 63 | xkbcommon, 64 | egl, 65 | wegl] 66 | 67 | sov_version = '"@0@"'.format(meson.project_version()) 68 | pkg_datadir = join_paths(get_option('prefix'), get_option('datadir')) / 'sov' 69 | add_project_arguments('-DPKG_DATADIR="' + pkg_datadir + '"', 70 | '-DSOV_VERSION=@0@'.format(sov_version), 71 | '-Wno-unused-parameter', 72 | language: 'c') 73 | 74 | if get_option('buildtype') == 'debug' 75 | add_project_arguments('-DDEBUG',language: 'c') 76 | endif 77 | 78 | sov_inc = include_directories( 79 | 'src/mt_math', 80 | 'src/mt_core', 81 | 'src/kinetic_ui', 82 | 'src/kinetic_ui/egl', 83 | 'src/kinetic_ui/handler', 84 | 'src/kinetic_ui/texture', 85 | 'src/sov', 86 | 'src/mt_core_ext') 87 | 88 | if build_machine.system() == 'freebsd' 89 | epoll = dependency('epoll-shim') 90 | pthread = dependency('threads') 91 | sov_dependencies += pthread 92 | sov_dependencies += epoll 93 | endif 94 | 95 | com_sources = ['src/sov/jsmn.c', 96 | 'src/sov/json.c', 97 | 'src/sov/tree.c', 98 | 'src/sov/gen.c', 99 | 'src/sov/ku_bitmap_ext.c', 100 | 101 | 'src/mt_core_ext/mt_string_ext.c', 102 | 'src/mt_core/mt_string.c', 103 | 'src/mt_core/mt_path.c', 104 | 'src/mt_core/mt_log.c', 105 | 'src/mt_core/mt_map.c', 106 | 'src/mt_core/mt_memory.c', 107 | 'src/mt_core/mt_number.c', 108 | 'src/mt_core/mt_time.c', 109 | 'src/mt_core/mt_vector.c', 110 | 'src/mt_core/mt_wrapper.c', 111 | 'src/mt_math/mt_matrix_4d.c', 112 | 113 | 'src/kinetic_ui/ku_event.c', 114 | 'src/kinetic_ui/ku_html.c', 115 | 'src/kinetic_ui/ku_css.c', 116 | 'src/kinetic_ui/egl/ku_gl.c', 117 | 'src/kinetic_ui/ku_rect.c', 118 | 'src/kinetic_ui/ku_bitmap.c', 119 | 'src/kinetic_ui/texture/tg_css.c', 120 | 'src/kinetic_ui/texture/tg_text.c', 121 | 'src/kinetic_ui/handler/vh_anim.c', 122 | 'src/kinetic_ui/handler/vh_button.c', 123 | 'src/kinetic_ui/handler/vh_drag.c', 124 | 'src/kinetic_ui/handler/vh_key.c', 125 | 'src/kinetic_ui/handler/vh_slider.c', 126 | 'src/kinetic_ui/ku_view.c', 127 | 'src/kinetic_ui/egl/ku_gl_atlas.c', 128 | 'src/kinetic_ui/egl/ku_gl_floatbuffer.c', 129 | 'src/kinetic_ui/egl/ku_gl_shader.c', 130 | 'src/kinetic_ui/ku_gen_html.c', 131 | 'src/kinetic_ui/ku_gen_css.c', 132 | 'src/kinetic_ui/ku_gen_type.c', 133 | 'src/kinetic_ui/ku_renderer_egl.c', 134 | 'src/kinetic_ui/ku_renderer_soft.c', 135 | 'src/kinetic_ui/ku_fontconfig.c', 136 | 'src/kinetic_ui/ku_connector_wayland.c', 137 | 'src/kinetic_ui/ku_window.c', 138 | 'src/kinetic_ui/ku_png.c', 139 | 'src/kinetic_ui/ku_draw.c', 140 | 'src/kinetic_ui/ku_text.c', 141 | 'src/kinetic_ui/ku_gen_textstyle.c'] + protos_src + protos_headers 142 | 143 | sov_sources = [com_sources, 'src/sov/sov.c'] 144 | draw_sources = [com_sources, 'src/sov/draw.c'] 145 | 146 | executable( 147 | 'sov', 148 | sov_sources, 149 | include_directories: [sov_inc], 150 | dependencies: sov_dependencies, 151 | install: true, 152 | ) 153 | 154 | executable( 155 | 'draw', 156 | draw_sources, 157 | include_directories: [sov_inc], 158 | dependencies: sov_dependencies, 159 | install: false, 160 | ) 161 | 162 | pkg_datadir = join_paths(get_option('prefix'), get_option('datadir')) / 'sov' 163 | 164 | install_data('res/html/main.html', install_dir : pkg_datadir / 'html' ) 165 | install_data('res/html/main.css', install_dir : pkg_datadir / 'html' ) 166 | 167 | install_data('contrib/systemd/sov.service', install_dir : get_option('libdir') / 'systemd' / 'user' ) 168 | install_data('contrib/systemd/sov.socket', install_dir : get_option('libdir') / 'systemd' / 'user' ) 169 | 170 | mt_core_test = executable( 171 | 'mt_core_test', 172 | ['src/mt_core/mt_log.c', 173 | 'src/mt_core/mt_memory.c', 174 | 'src/mt_core/mt_vector.c', 175 | 'src/mt_core/mt_map.c', 176 | 'src/mt_core/mt_string.c', 177 | 'src/mt_core/mt_channel.c', 178 | 'src/mt_core/mt_path.c', 179 | 'src/mt_core_test/mt_core_test.c', 180 | 'src/mt_core_test/mt_memory_test.c', 181 | 'src/mt_core_test/mt_vector_test.c', 182 | 'src/mt_core_test/mt_map_test.c', 183 | 'src/mt_core_test/mt_string_test.c', 184 | 'src/mt_core_test/mt_channel_test.c', 185 | 'src/mt_core_test/mt_path_test.c' 186 | ], 187 | include_directories: ['src/mt_core'], 188 | dependencies: sov_dependencies) 189 | 190 | test('MT_CORE_TEST', mt_core_test) 191 | 192 | scripttests = find_program('tst/runtests.sh') 193 | 194 | test('SCRIPTED TESTS', scripttests, timeout: 0, workdir : meson.current_source_dir(), args : [meson.current_build_dir(),meson.current_source_dir()]) 195 | -------------------------------------------------------------------------------- /res/html/main.css: -------------------------------------------------------------------------------- 1 | #main { 2 | border-radius: 10px; 3 | background-color: #00000044; 4 | } 5 | 6 | #base { 7 | margin: 10px; 8 | } 9 | 10 | .fullscale { 11 | height: 100%; 12 | width: 100%; 13 | } 14 | 15 | .colflex { 16 | display: flex; 17 | flex-direction: column; 18 | } 19 | 20 | .rowflex { 21 | display: flex; 22 | flex-direction: row; 23 | } 24 | 25 | .workspace { 26 | margin: 10px; 27 | border-radius: 8px; 28 | background-color: #000000FF; 29 | border-width: 1px; 30 | border-color: #555555FF; 31 | } 32 | 33 | .window { 34 | width: 100px; 35 | height: 80px; 36 | background-color: #222222FF; 37 | border-radius: 8px; 38 | border-width: 1px; 39 | border-color: #BCBCBCFF; 40 | } 41 | 42 | .window_active { 43 | width: 100px; 44 | height: 80px; 45 | background-color: #444444FF; 46 | border-radius: 8px; 47 | border-width: 1px; 48 | border-color: #BCBCBCFF; 49 | } 50 | 51 | .title { 52 | width: 100%; 53 | height: 21px; 54 | margin-top: 4px; 55 | margin-left: 4px; 56 | margin-right: 4px; 57 | margin-bottom: 2px; 58 | color: #FFFFFFFF; 59 | font-size: 16px; 60 | font-family: "Ubuntu Mono:style=Bold:size=14"; 61 | } 62 | 63 | .content { 64 | width: 100%; 65 | height: 100%; 66 | margin-left: 4px; 67 | margin-right: 4px; 68 | color: #999999FF; 69 | vertical-align: top; 70 | font-size: 14px; 71 | font-family: "Ubuntu Mono:style=Bold:size=12"; 72 | word-wrap: break-word; 73 | line-height: 12px; 74 | } 75 | 76 | .number { 77 | width: 20px; 78 | height: 20px; 79 | right: -14px; 80 | top: -9px; 81 | color: #FFFFFFFF; 82 | font-size: 18px; 83 | font-family: "Ubuntu Mono:style=Bold:size=16"; 84 | } 85 | -------------------------------------------------------------------------------- /res/html/main.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | 16 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milgra/sov/19809ae535f8417098020f86ceefa25dbd3c5a90/screenshot.png -------------------------------------------------------------------------------- /src/kinetic_ui/egl/ku_gl_atlas.c: -------------------------------------------------------------------------------- 1 | #ifndef _ku_gl_atlas_h 2 | #define _ku_gl_atlas_h 3 | 4 | #include "mt_map.c" 5 | #include "mt_matrix_4d.c" 6 | #include "mt_vector_4d.c" 7 | 8 | typedef struct _ku_gl_atlas_coords_t ku_gl_atlas_coords_t; 9 | struct _ku_gl_atlas_coords_t 10 | { 11 | float ltx; 12 | float lty; 13 | float rbx; 14 | float rby; 15 | int x; 16 | int y; 17 | int w; 18 | int h; 19 | }; 20 | 21 | typedef struct _ku_gl_atlas_t ku_gl_atlas_t; 22 | struct _ku_gl_atlas_t 23 | { 24 | mt_map_t* coords; 25 | char* blocks; 26 | char is_full; 27 | int width; 28 | int height; 29 | int cols; 30 | int rows; 31 | }; 32 | 33 | ku_gl_atlas_t* ku_gl_atlas_new(int w, int h); 34 | void ku_gl_atlas_del(void* p); 35 | char ku_gl_atlas_has(ku_gl_atlas_t* tm, char* id); 36 | ku_gl_atlas_coords_t ku_gl_atlas_get(ku_gl_atlas_t* tm, char* id); 37 | int ku_gl_atlas_put(ku_gl_atlas_t* tm, char* id, int w, int h); 38 | 39 | #endif 40 | 41 | #if __INCLUDE_LEVEL__ == 0 42 | 43 | #include "mt_memory.c" 44 | #include 45 | 46 | void ku_gl_atlas_desc(void* p, int level) 47 | { 48 | ku_gl_atlas_t* tm = p; 49 | printf("tm w %i h %i", tm->width, tm->height); 50 | } 51 | 52 | void ku_gl_atlas_desc_blocks(void* p, int level) 53 | { 54 | printf("tm blocks\n"); 55 | } 56 | 57 | ku_gl_atlas_t* ku_gl_atlas_new(int w, int h) 58 | { 59 | int cols = w / 32; 60 | int rows = h / 32; 61 | 62 | ku_gl_atlas_t* tm = CAL(sizeof(ku_gl_atlas_t), ku_gl_atlas_del, ku_gl_atlas_desc); 63 | tm->coords = mt_map_new(); 64 | tm->blocks = CAL(sizeof(char) * cols * rows, NULL, ku_gl_atlas_desc_blocks); 65 | tm->width = w; 66 | tm->height = h; 67 | tm->cols = cols; 68 | tm->rows = rows; 69 | 70 | return tm; 71 | } 72 | 73 | void ku_gl_atlas_del(void* p) 74 | { 75 | ku_gl_atlas_t* tm = (ku_gl_atlas_t*) p; 76 | REL(tm->coords); 77 | REL(tm->blocks); 78 | } 79 | 80 | char ku_gl_atlas_has(ku_gl_atlas_t* tm, char* id) 81 | { 82 | v4_t* coords = mt_map_get(tm->coords, id); 83 | if (coords) return 1; 84 | return 0; 85 | } 86 | 87 | ku_gl_atlas_coords_t ku_gl_atlas_get(ku_gl_atlas_t* tm, char* id) 88 | { 89 | ku_gl_atlas_coords_t* coords = mt_map_get(tm->coords, id); 90 | if (coords) return *coords; 91 | return (ku_gl_atlas_coords_t){0}; 92 | } 93 | 94 | int ku_gl_atlas_put(ku_gl_atlas_t* tm, char* id, int w, int h) 95 | { 96 | if (w > tm->width || h > tm->height) return -1; // too big bitmap 97 | 98 | // get size of incoming rect 99 | int sx = ceil((float) w / 32.0); 100 | int sy = ceil((float) h / 32.0); 101 | 102 | int r = 0; // row 103 | int c = 0; // col 104 | int s = 0; // success 105 | 106 | for (r = 0; r < tm->rows; r++) 107 | { 108 | for (c = 0; c < tm->cols; c++) 109 | { 110 | int i = r * tm->cols + c; 111 | 112 | // if block is free, check if width and height of new rect fits 113 | 114 | if (tm->blocks[i] == 0) 115 | { 116 | s = 1; // assume success 117 | if (c + sx < tm->cols) 118 | { 119 | for (int tc = c; tc < c + sx; tc++) 120 | { 121 | int ti = r * tm->cols + tc; // test index 122 | if (tm->blocks[ti] == 1) 123 | { 124 | s = 0; // if block is occupied test is failed 125 | break; 126 | } 127 | } 128 | } 129 | else 130 | s = 0; // doesn't fit 131 | 132 | if (r + sy < tm->rows && s == 1) 133 | { 134 | for (int tr = r; tr < r + sy; tr++) 135 | { 136 | int ti = tr * tm->cols + c; // test index 137 | if (tm->blocks[ti] == 1) 138 | { 139 | s = 0; // if block is occupied test is failed 140 | break; 141 | } 142 | } 143 | } 144 | else 145 | s = 0; // doesn't fit 146 | } 147 | if (s == 1) break; 148 | } 149 | if (s == 1) break; 150 | } 151 | 152 | if (s == 1) 153 | { 154 | // flip blocks to occupied 155 | for (int nr = r; nr < r + sy; nr++) 156 | { 157 | for (int nc = c; nc < c + sx; nc++) 158 | { 159 | int ni = nr * tm->cols + nc; 160 | tm->blocks[ni] = 1; 161 | } 162 | } 163 | 164 | int ncx = c * 32; 165 | int ncy = r * 32; 166 | int rbx = ncx + w; 167 | int rby = ncy + h; 168 | 169 | ku_gl_atlas_coords_t* coords = HEAP( 170 | ((ku_gl_atlas_coords_t){ 171 | .ltx = (float) ncx / (float) tm->width, 172 | .lty = (float) ncy / (float) tm->height, 173 | .rbx = (float) rbx / (float) tm->width, 174 | .rby = (float) rby / (float) tm->height, 175 | .x = ncx, 176 | .y = ncy, 177 | .w = w, 178 | .h = h})); 179 | 180 | MPUTR(tm->coords, id, coords); 181 | } 182 | else 183 | return -2; // texmap is full 184 | 185 | return 0; // success 186 | } 187 | 188 | #endif 189 | -------------------------------------------------------------------------------- /src/kinetic_ui/egl/ku_gl_floatbuffer.c: -------------------------------------------------------------------------------- 1 | #ifndef ku_floatbuffer_h 2 | #define ku_floatbuffer_h 3 | 4 | #include "mt_memory.c" 5 | #include 6 | #include 7 | 8 | typedef struct ku_floatbuffer_t ku_floatbuffer_t; 9 | struct ku_floatbuffer_t 10 | { 11 | GLfloat* data; 12 | size_t pos; 13 | size_t cap; 14 | char changed; 15 | }; 16 | 17 | ku_floatbuffer_t* ku_floatbuffer_new(void); 18 | void ku_floatbuffer_del(void* fb); 19 | void ku_floatbuffer_reset(ku_floatbuffer_t* fb); 20 | void ku_floatbuffer_add(ku_floatbuffer_t* fb, GLfloat* data, size_t count); 21 | 22 | #endif 23 | 24 | #if __INCLUDE_LEVEL__ == 0 25 | 26 | void ku_floatbuffer_desc(void* p, int level) 27 | { 28 | printf("fb"); 29 | } 30 | 31 | void ku_floatbuffer_desc_data(void* p, int level) 32 | { 33 | printf("fb data"); 34 | } 35 | 36 | ku_floatbuffer_t* ku_floatbuffer_new() 37 | { 38 | ku_floatbuffer_t* fb = CAL(sizeof(ku_floatbuffer_t), ku_floatbuffer_del, ku_floatbuffer_desc); 39 | fb->data = CAL(sizeof(GLfloat) * 10, NULL, ku_floatbuffer_desc_data); 40 | fb->pos = 0; 41 | fb->cap = 10; 42 | 43 | return fb; 44 | } 45 | 46 | void ku_floatbuffer_del(void* pointer) 47 | { 48 | ku_floatbuffer_t* fb = pointer; 49 | REL(fb->data); 50 | } 51 | 52 | void ku_floatbuffer_reset(ku_floatbuffer_t* fb) 53 | { 54 | fb->pos = 0; 55 | } 56 | 57 | void ku_floatbuffer_expand(ku_floatbuffer_t* fb) 58 | { 59 | assert(fb->cap < SIZE_MAX / 2); 60 | fb->cap *= 2; 61 | fb->data = mt_memory_realloc(fb->data, sizeof(void*) * fb->cap); 62 | } 63 | 64 | void ku_floatbuffer_add(ku_floatbuffer_t* fb, GLfloat* data, size_t count) 65 | { 66 | while (fb->pos + count >= fb->cap) ku_floatbuffer_expand(fb); 67 | memcpy(fb->data + fb->pos, data, sizeof(GLfloat) * count); 68 | fb->pos += count; 69 | fb->changed = 1; 70 | } 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /src/kinetic_ui/egl/ku_gl_shader.c: -------------------------------------------------------------------------------- 1 | #ifndef ku_gl_shader_h 2 | #define ku_gl_shader_h 3 | 4 | #include 5 | 6 | typedef struct _glsha_t 7 | { 8 | GLuint name; 9 | GLint uni_loc[13]; 10 | } glsha_t; 11 | 12 | glsha_t ku_gl_shader_create( 13 | const char* vertex_source, 14 | const char* fragment_source, 15 | int attribute_locations_length, 16 | const char** attribute_structure, 17 | int uniform_locations_length, 18 | const char** uniform_structure); 19 | 20 | #endif 21 | 22 | #if __INCLUDE_LEVEL__ == 0 23 | 24 | #include 25 | 26 | GLuint ku_gl_shader_compile(GLenum type, const GLchar* source) 27 | { 28 | GLint status, logLength, realLength; 29 | GLuint shader = 0; 30 | 31 | status = 0; 32 | shader = glCreateShader(type); 33 | 34 | if (shader > 0) 35 | { 36 | glShaderSource(shader, 1, &source, NULL); 37 | glCompileShader(shader); 38 | glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength); 39 | 40 | if (logLength > 0) 41 | { 42 | GLchar log[logLength]; 43 | 44 | glGetShaderInfoLog(shader, logLength, &realLength, log); 45 | 46 | printf("Shader compile log: %s\n", log); 47 | } 48 | 49 | glGetShaderiv(shader, GL_COMPILE_STATUS, &status); 50 | 51 | if (status != GL_TRUE) 52 | return 0; 53 | } 54 | else 55 | printf("Cannot create shader\n"); 56 | 57 | return shader; 58 | } 59 | 60 | int ku_gl_shader_link(GLuint program) 61 | { 62 | GLint status, logLength, realLength; 63 | 64 | glLinkProgram(program); 65 | glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength); 66 | 67 | if (logLength > 0) 68 | { 69 | GLchar log[logLength]; 70 | glGetProgramInfoLog(program, logLength, &realLength, log); 71 | printf("Program link log : %i %s\n", realLength, log); 72 | } 73 | 74 | glGetProgramiv(program, GL_LINK_STATUS, &status); 75 | if (status == GL_TRUE) 76 | return 1; 77 | return 0; 78 | } 79 | 80 | glsha_t ku_gl_shader_create( 81 | const char* vertex_source, 82 | const char* fragment_source, 83 | int attribute_locations_length, 84 | const char** attribute_structure, 85 | int uniform_locations_length, 86 | const char** uniform_structure) 87 | { 88 | glsha_t sh = {0}; 89 | 90 | sh.name = glCreateProgram(); 91 | 92 | GLuint vertex_shader = ku_gl_shader_compile(GL_VERTEX_SHADER, vertex_source); 93 | if (vertex_shader == 0) printf("Failed to compile vertex shader : %s\n", vertex_source); 94 | 95 | GLuint fragment_shader = ku_gl_shader_compile(GL_FRAGMENT_SHADER, fragment_source); 96 | if (fragment_shader == 0) printf("Failed to compile fragment shader : %s\n", fragment_source); 97 | 98 | glAttachShader(sh.name, vertex_shader); 99 | glAttachShader(sh.name, fragment_shader); 100 | 101 | for (int index = 0; index < attribute_locations_length; index++) 102 | { 103 | const GLchar* name = attribute_structure[index]; 104 | glBindAttribLocation(sh.name, index, name); 105 | } 106 | 107 | int success = ku_gl_shader_link(sh.name); 108 | 109 | if (success == 1) 110 | { 111 | for (int index = 0; index < uniform_locations_length; index++) 112 | { 113 | const GLchar* name = uniform_structure[index]; 114 | GLint location = glGetUniformLocation(sh.name, name); 115 | sh.uni_loc[index] = location; 116 | } 117 | } 118 | else 119 | printf("Failed to link shader program\n"); 120 | 121 | if (vertex_shader > 0) 122 | { 123 | glDetachShader(sh.name, vertex_shader); 124 | glDeleteShader(vertex_shader); 125 | } 126 | 127 | if (fragment_shader > 0) 128 | { 129 | glDetachShader(sh.name, fragment_shader); 130 | glDeleteShader(fragment_shader); 131 | } 132 | 133 | return sh; 134 | } 135 | 136 | #endif 137 | -------------------------------------------------------------------------------- /src/kinetic_ui/handler/vh_button.c: -------------------------------------------------------------------------------- 1 | #ifndef vh_button_h 2 | #define vh_button_h 3 | 4 | #include "ku_view.c" 5 | 6 | typedef enum _vh_button_type_t 7 | { 8 | VH_BUTTON_NORMAL, 9 | VH_BUTTON_TOGGLE 10 | } vh_button_type_t; 11 | 12 | typedef enum _vh_button_state_t 13 | { 14 | VH_BUTTON_UP, 15 | VH_BUTTON_DOWN 16 | } vh_button_state_t; 17 | 18 | typedef struct _vh_button_t vh_button_t; 19 | 20 | enum vh_button_event_id 21 | { 22 | VH_BUTTON_EVENT 23 | }; 24 | 25 | typedef struct _vh_button_event_t 26 | { 27 | enum vh_button_event_id id; 28 | vh_button_t* vh; 29 | ku_view_t* view; 30 | ku_event_t ev; 31 | } vh_button_event_t; 32 | 33 | struct _vh_button_t 34 | { 35 | void (*on_event)(vh_button_event_t); 36 | vh_button_type_t type; 37 | vh_button_state_t state; 38 | 39 | ku_view_t* offview; 40 | ku_view_t* onview; 41 | char enabled; 42 | }; 43 | 44 | void vh_button_add(ku_view_t* view, vh_button_type_t type, void (*on_event)(vh_button_event_t)); 45 | void vh_button_set_state(ku_view_t* view, vh_button_state_t state); 46 | void vh_button_set_enabled(ku_view_t* view, int flag); 47 | 48 | #endif 49 | 50 | #if __INCLUDE_LEVEL__ == 0 51 | 52 | #include "vh_anim.c" 53 | 54 | void vh_button_on_anim(vh_anim_event_t event) 55 | { 56 | ku_view_t* btnview = (ku_view_t*) event.userdata; 57 | vh_button_t* vh = btnview->evt_han_data; 58 | 59 | // if offview alpha is 0 and state is released 60 | 61 | if (vh->type == VH_BUTTON_NORMAL) 62 | { 63 | if (vh->offview->texture.alpha < 0.0001 && event.view == vh->offview) 64 | { 65 | vh_anim_alpha(vh->offview, 0.0, 1.0, 10, AT_LINEAR); 66 | } 67 | } 68 | } 69 | 70 | int vh_button_evt(ku_view_t* view, ku_event_t ev) 71 | { 72 | vh_button_t* vh = view->evt_han_data; 73 | 74 | if (vh->enabled) 75 | { 76 | if (ev.type == KU_EVENT_MOUSE_DOWN) 77 | { 78 | if (vh->type == VH_BUTTON_NORMAL) 79 | { 80 | vh->state = VH_BUTTON_DOWN; 81 | 82 | if (vh->offview) 83 | vh_anim_alpha(vh->offview, 1.0, 0.0, 10, AT_LINEAR); 84 | if (vh->onview) 85 | vh_anim_alpha(vh->onview, 0.0, 1.0, 10, AT_LINEAR); 86 | } 87 | } 88 | else if (ev.type == KU_EVENT_MOUSE_UP) 89 | { 90 | if (vh->type == VH_BUTTON_TOGGLE) 91 | { 92 | if (vh->state == VH_BUTTON_UP) 93 | { 94 | vh->state = VH_BUTTON_DOWN; 95 | if (vh->offview) 96 | vh_anim_alpha(vh->offview, 1.0, 0.0, 10, AT_LINEAR); 97 | if (vh->onview) 98 | vh_anim_alpha(vh->onview, 0.0, 1.0, 10, AT_LINEAR); 99 | } 100 | else 101 | { 102 | vh->state = VH_BUTTON_UP; 103 | if (vh->offview) 104 | vh_anim_alpha(vh->offview, 0.0, 1.0, 10, AT_LINEAR); 105 | if (vh->onview) 106 | vh_anim_alpha(vh->onview, 1.0, 0.0, 10, AT_LINEAR); 107 | } 108 | 109 | vh_button_event_t event = {.id = VH_BUTTON_EVENT, .view = view, .vh = vh, .ev = ev}; 110 | if (vh->on_event) 111 | (*vh->on_event)(event); 112 | } 113 | else 114 | { 115 | vh->state = VH_BUTTON_UP; 116 | 117 | vh_button_event_t event = {.id = VH_BUTTON_EVENT, .view = view, .vh = vh, .ev = ev}; 118 | if (vh->on_event) 119 | (*vh->on_event)(event); 120 | 121 | /* if (vh->offview) vh_anim_alpha(vh->offview, 1.0, 0.0, 10, AT_LINEAR); */ 122 | /* if (vh->onview) vh_anim_alpha(vh->onview, 0.0, 1.0, 10, AT_LINEAR); */ 123 | } 124 | } 125 | } 126 | 127 | return 0; 128 | } 129 | 130 | void vh_button_set_state(ku_view_t* view, vh_button_state_t state) 131 | { 132 | vh_button_t* vh = view->evt_han_data; 133 | 134 | if (vh->enabled) 135 | { 136 | vh->state = state; 137 | 138 | if (state) 139 | { 140 | if (vh->offview) 141 | vh_anim_alpha(vh->offview, 1.0, 0.0, 10, AT_LINEAR); 142 | if (vh->onview) 143 | vh_anim_alpha(vh->onview, 0.0, 1.0, 10, AT_LINEAR); 144 | } 145 | else 146 | { 147 | if (vh->offview) 148 | vh_anim_alpha(vh->offview, 0.0, 1.0, 10, AT_LINEAR); 149 | if (vh->onview) 150 | vh_anim_alpha(vh->onview, 1.0, 0.0, 10, AT_LINEAR); 151 | } 152 | } 153 | } 154 | 155 | void vh_button_del(void* p) 156 | { 157 | /* vh_button_t* vh = p; */ 158 | } 159 | 160 | void vh_button_desc(void* p, int level) 161 | { 162 | printf("vh_button"); 163 | } 164 | 165 | void vh_button_add(ku_view_t* view, vh_button_type_t type, void (*on_event)(vh_button_event_t)) 166 | { 167 | assert(view->evt_han == NULL && view->evt_han_data == NULL); 168 | 169 | vh_button_t* vh = CAL(sizeof(vh_button_t), vh_button_del, vh_button_desc); 170 | vh->on_event = on_event; 171 | vh->type = type; 172 | vh->state = VH_BUTTON_UP; 173 | vh->enabled = 1; 174 | 175 | if (view->views->length > 0) 176 | { 177 | vh->offview = view->views->data[0]; 178 | vh_anim_add(vh->offview, vh_button_on_anim, view); 179 | } 180 | if (view->views->length > 1) 181 | { 182 | vh->type = VH_BUTTON_TOGGLE; 183 | vh->onview = view->views->data[1]; 184 | vh_anim_add(vh->onview, vh_button_on_anim, view); 185 | } 186 | 187 | if (vh->offview) 188 | ku_view_set_texture_alpha(vh->offview, 1.0, 0); 189 | if (vh->onview) 190 | ku_view_set_texture_alpha(vh->onview, 0.0, 0); 191 | 192 | view->evt_han = vh_button_evt; 193 | view->evt_han_data = vh; 194 | } 195 | 196 | void vh_button_set_enabled(ku_view_t* view, int flag) 197 | { 198 | vh_button_t* vh = view->evt_han_data; 199 | 200 | if (flag) 201 | { 202 | if (vh->enabled == 0 && vh->offview) 203 | vh_anim_alpha(vh->offview, 0.3, 1.0, 10, AT_LINEAR); 204 | } 205 | else 206 | { 207 | if (vh->enabled == 1 && vh->offview) 208 | vh_anim_alpha(vh->offview, 1.0, 0.3, 10, AT_LINEAR); 209 | } 210 | 211 | vh->enabled = flag; 212 | } 213 | 214 | #endif 215 | -------------------------------------------------------------------------------- /src/kinetic_ui/handler/vh_cv_body.c: -------------------------------------------------------------------------------- 1 | /* content view body */ 2 | 3 | #ifndef vh_cv_body_h 4 | #define vh_cv_body_h 5 | 6 | #include "ku_view.c" 7 | 8 | typedef struct _vh_cv_body_t 9 | { 10 | void* userdata; 11 | 12 | ku_view_t* content; 13 | float cw; // content width 14 | float ch; // content height 15 | float px; 16 | float py; 17 | float zoom; 18 | } vh_cv_body_t; 19 | 20 | void vh_cv_body_attach( 21 | ku_view_t* view, 22 | void* userdata); 23 | 24 | void vh_cv_body_set_content_size( 25 | ku_view_t* view, 26 | int cw, 27 | int ch); 28 | 29 | void vh_cv_body_move( 30 | ku_view_t* view, 31 | float dx, 32 | float dy); 33 | 34 | void vh_cv_body_zoom( 35 | ku_view_t* view, 36 | float s, 37 | int x, 38 | int y); 39 | 40 | void vh_cv_body_reset( 41 | ku_view_t* view); 42 | 43 | void vh_cv_body_hjump( 44 | ku_view_t* view, 45 | float dx); 46 | 47 | void vh_cv_body_vjump( 48 | ku_view_t* view, 49 | int topindex); 50 | 51 | #endif 52 | 53 | #if __INCLUDE_LEVEL__ == 0 54 | 55 | #include "tg_scaledimg.c" 56 | 57 | void vh_cv_body_del(void* p) 58 | { 59 | } 60 | 61 | void vh_cv_body_desc(void* p, int level) 62 | { 63 | printf("vh_cv_body"); 64 | } 65 | 66 | void vh_cv_body_attach( 67 | ku_view_t* view, 68 | void* userdata) 69 | { 70 | assert(view->evt_han == NULL && view->evt_han_data == NULL); 71 | 72 | vh_cv_body_t* vh = CAL(sizeof(vh_cv_body_t), vh_cv_body_del, vh_cv_body_desc); 73 | vh->userdata = userdata; 74 | vh->content = view->views->data[0]; 75 | vh->zoom = 1.0; 76 | 77 | vh->cw = 1; 78 | vh->ch = 1; 79 | 80 | view->evt_han_data = vh; 81 | } 82 | 83 | void vh_cv_body_set_content_size( 84 | ku_view_t* view, 85 | int cw, 86 | int ch) 87 | { 88 | vh_cv_body_t* vh = view->evt_han_data; 89 | 90 | vh->cw = cw; 91 | vh->ch = ch; 92 | 93 | ku_rect_t lf = view->frame.local; // local frame 94 | 95 | float cr = (float) ch / (float) cw; // content aspect ratio 96 | 97 | /* fit width first */ 98 | 99 | float nw = lf.w; 100 | float nh = nw * cr; 101 | 102 | vh->zoom = (float) nw / cw; 103 | 104 | if (nh > lf.h) 105 | { 106 | cr = lf.h / nh; 107 | 108 | nh = lf.h; 109 | nw *= cr; 110 | vh->zoom = (float) nh / ch; 111 | } 112 | 113 | ku_rect_t frame = vh->content->frame.local; 114 | frame.x = (lf.w - nw) / 2.0; 115 | frame.y = (lf.h - nh) / 2.0; 116 | frame.w = nw; 117 | frame.h = nh; 118 | 119 | ku_view_set_frame(vh->content, frame); 120 | 121 | tg_scaledimg_set_content_size(vh->content, cw, ch); 122 | tg_scaledimg_gen(vh->content); 123 | } 124 | 125 | void vh_cv_body_move( 126 | ku_view_t* view, 127 | float dx, 128 | float dy) 129 | { 130 | vh_cv_body_t* vh = view->evt_han_data; 131 | 132 | ku_rect_t frame = vh->content->frame.local; 133 | frame.x += dx; 134 | frame.y += dy; 135 | ku_view_set_frame(vh->content, frame); 136 | } 137 | 138 | void vh_cv_body_zoom( 139 | ku_view_t* view, 140 | float z, 141 | int x, 142 | int y) 143 | { 144 | vh_cv_body_t* vh = view->evt_han_data; 145 | 146 | ku_rect_t gf = vh->content->frame.global; 147 | ku_rect_t lf = vh->content->frame.local; 148 | 149 | /* partial width and height from mouse position */ 150 | 151 | float pw = (float) x - gf.x; 152 | float ph = (float) y - gf.y; 153 | 154 | /* ratios */ 155 | 156 | float rw = pw / gf.w; 157 | float rh = ph / gf.h; 158 | 159 | vh->zoom = z; 160 | if (vh->zoom < 0.001) 161 | vh->zoom = 0.001; 162 | 163 | float nw = vh->cw * vh->zoom; 164 | float nh = vh->ch * vh->zoom; 165 | 166 | lf.x = (float) x - rw * nw - view->frame.global.x; 167 | lf.y = (float) y - rh * nh - view->frame.global.y; 168 | lf.w = nw; 169 | lf.h = nh; 170 | 171 | ku_view_set_frame(vh->content, lf); 172 | tg_scaledimg_gen(vh->content); 173 | } 174 | 175 | void vh_cv_body_reset( 176 | ku_view_t* view) 177 | { 178 | } 179 | 180 | void vh_cv_body_hjump( 181 | ku_view_t* view, 182 | float x) 183 | { 184 | } 185 | 186 | void vh_cv_body_vjump( 187 | ku_view_t* view, 188 | int topindex) 189 | { 190 | } 191 | 192 | #endif 193 | -------------------------------------------------------------------------------- /src/kinetic_ui/handler/vh_cv_scrl.c: -------------------------------------------------------------------------------- 1 | #ifndef vh_cv_scrl_h 2 | #define vh_cv_scrl_h 3 | 4 | #include "ku_view.c" 5 | #include "vh_cv_body.c" 6 | 7 | typedef struct _vh_cv_scrl_t 8 | { 9 | ku_view_t* tbody_view; 10 | ku_view_t* vert_v; 11 | ku_view_t* hori_v; 12 | int state; // 0 scroll 1 open 2 close 13 | int steps; 14 | size_t item_cnt; 15 | void* userdata; 16 | } vh_cv_scrl_t; 17 | 18 | void vh_cv_scrl_attach( 19 | ku_view_t* view, 20 | ku_view_t* tbody_view, 21 | void* userdata); 22 | 23 | void vh_cv_scrl_update(ku_view_t* view); 24 | void vh_cv_scrl_show(ku_view_t* view); 25 | void vh_cv_scrl_hide(ku_view_t* view); 26 | void vh_cv_scrl_set_item_count(ku_view_t* view, size_t count); 27 | void vh_cv_scrl_scroll_v(ku_view_t* view, int y); 28 | void vh_cv_scrl_scroll_h(ku_view_t* view, int x); 29 | 30 | #endif 31 | 32 | #if __INCLUDE_LEVEL__ == 0 33 | 34 | void vh_cv_scrl_del(void* p) 35 | { 36 | vh_cv_scrl_t* vh = p; 37 | REL(vh->vert_v); 38 | REL(vh->hori_v); 39 | } 40 | 41 | void vh_cv_scrl_desc(void* p, int level) 42 | { 43 | printf("vh_cv_scrl"); 44 | } 45 | 46 | void vh_cv_scrl_attach( 47 | ku_view_t* view, 48 | ku_view_t* tbody_view, 49 | void* userdata) 50 | { 51 | vh_cv_scrl_t* vh = CAL(sizeof(vh_cv_scrl_t), vh_cv_scrl_del, vh_cv_scrl_desc); 52 | vh->userdata = userdata; 53 | vh->tbody_view = tbody_view; 54 | 55 | assert(view->views->length > 1); 56 | 57 | vh->vert_v = RET(view->views->data[0]); 58 | vh->hori_v = RET(view->views->data[1]); 59 | 60 | ku_view_set_texture_alpha(vh->hori_v, 0.0, 0); 61 | ku_view_set_texture_alpha(vh->vert_v, 0.0, 0); 62 | 63 | view->evt_han_data = vh; 64 | } 65 | 66 | void vh_cv_scrl_set_item_count(ku_view_t* view, size_t count) 67 | { 68 | vh_cv_scrl_t* vh = view->evt_han_data; 69 | 70 | vh->item_cnt = count; 71 | } 72 | 73 | void vh_cv_scrl_update(ku_view_t* view) 74 | { 75 | vh_cv_scrl_t* vh = view->evt_han_data; 76 | vh_cv_body_t* bvh = vh->tbody_view->evt_han_data; 77 | 78 | ku_rect_t vf = view->frame.local; 79 | ku_rect_t cf = bvh->content->frame.local; 80 | 81 | float pratio = -cf.y / cf.h; 82 | float sratio = cf.h / vf.h; 83 | 84 | if (sratio > 1.0) 85 | { 86 | float hth = (vf.h - vh->hori_v->frame.local.h) * (1 / sratio); 87 | float pos = (vf.h - vh->hori_v->frame.local.h) * pratio; 88 | 89 | if (vh->state == 2) 90 | { 91 | pos += hth / 2.0; 92 | hth = 1.0; 93 | } 94 | 95 | ku_rect_t frame = vh->vert_v->frame.local; 96 | frame.h += (hth - frame.h) / 2.0; 97 | frame.y += (pos - frame.y) / 2.0; 98 | 99 | ku_view_set_frame(vh->vert_v, frame); 100 | } 101 | 102 | pratio = -cf.x / cf.w; 103 | sratio = cf.w / vf.w; 104 | 105 | if (sratio > 1.0) 106 | { 107 | float wth = (vf.w - vh->vert_v->frame.local.w) * (1 / sratio); 108 | float pos = (vf.w - vh->vert_v->frame.local.w) * pratio; 109 | 110 | if (vh->state == 2) 111 | { 112 | pos += wth / 2.0; 113 | wth = 1.0; 114 | } 115 | 116 | ku_rect_t frame = vh->hori_v->frame.local; 117 | frame.w += (wth - frame.w) / 2.0; 118 | frame.x += (pos - frame.x) / 2.0; 119 | 120 | ku_view_set_frame(vh->hori_v, frame); 121 | } 122 | 123 | if (vh->state > 0) 124 | { 125 | vh->steps += 1; 126 | if (vh->steps == 5) 127 | { 128 | if (vh->state == 2) 129 | { 130 | ku_view_set_texture_alpha(vh->hori_v, 0.0, 0); 131 | ku_view_set_texture_alpha(vh->vert_v, 0.0, 0); 132 | } 133 | vh->state = 0; 134 | } 135 | } 136 | } 137 | 138 | void vh_cv_scrl_show(ku_view_t* view) 139 | { 140 | vh_cv_scrl_t* vh = view->evt_han_data; 141 | 142 | vh->state = 1; 143 | vh->steps = 0; 144 | ku_view_set_texture_alpha(vh->hori_v, 1.0, 0); 145 | ku_view_set_texture_alpha(vh->vert_v, 1.0, 0); 146 | } 147 | 148 | void vh_cv_scrl_hide(ku_view_t* view) 149 | { 150 | vh_cv_scrl_t* vh = view->evt_han_data; 151 | vh->state = 2; 152 | vh->steps = 0; 153 | } 154 | 155 | void vh_cv_scrl_scroll_v(ku_view_t* view, int y) 156 | { 157 | /* vh_cv_scrl_t* vh = view->evt_han_data; */ 158 | /* vh_cv_body_t* bvh = vh->tbody_view->evt_han_data; */ 159 | 160 | /* if (bvh->items->length > 0 && vh->item_cnt > 0) */ 161 | /* { */ 162 | /* // int vert_pos = bvh->top_index; */ 163 | /* int vert_vis = bvh->bot_index - bvh->top_index; */ 164 | /* int vert_max = vh->item_cnt; */ 165 | 166 | /* if (vert_max > 1) */ 167 | /* { */ 168 | /* float sratio = (float) vert_vis / (float) vert_max; */ 169 | /* float height = (view->frame.local.h - view->frame.local.h * sratio); */ 170 | /* float pratio = (float) y / height; */ 171 | 172 | /* if (pratio < 0.0) pratio = 0.0; */ 173 | /* if (pratio > 1.0) pratio = 1.0; */ 174 | /* int topindex = pratio * (vert_max - vert_vis); */ 175 | 176 | /* vh_cv_body_vjump(vh->tbody_view, topindex); */ 177 | 178 | /* ku_rect_t frame = vh->vert_v->frame.local; */ 179 | /* frame.h = view->frame.local.h * sratio; */ 180 | /* frame.y = y; */ 181 | 182 | /* ku_view_set_frame(vh->vert_v, frame); */ 183 | /* } */ 184 | /* } */ 185 | } 186 | 187 | void vh_cv_scrl_scroll_h(ku_view_t* view, int x) 188 | { 189 | /* vh_cv_scrl_t* vh = view->evt_han_data; */ 190 | /* vh_cv_body_t* bvh = vh->tbody_view->evt_han_data; */ 191 | 192 | /* if (bvh->items->length > 0 && vh->item_cnt > 0) */ 193 | /* { */ 194 | /* ku_view_t* head = bvh->items->data[0]; */ 195 | 196 | /* // float hori_pos = -head->frame.local.x; */ 197 | /* float hori_vis = view->frame.local.w; */ 198 | /* float hori_max = head->frame.local.w; */ 199 | 200 | /* if (hori_max > 1.0) */ 201 | /* { */ 202 | /* float sratio = (float) hori_vis / (float) hori_max; */ 203 | /* float width = (view->frame.local.w - view->frame.local.w * sratio); */ 204 | /* float pratio = (float) x / width; */ 205 | 206 | /* if (pratio < 0.0) pratio = 0.0; */ 207 | /* if (pratio > 1.0) pratio = 1.0; */ 208 | /* float dx = pratio * (hori_max - hori_vis); */ 209 | 210 | /* vh_cv_body_hjump(vh->tbody_view, -dx); */ 211 | /* vh_cv_head_jump(vh->thead_view, -dx); */ 212 | 213 | /* ku_rect_t frame = vh->hori_v->frame.local; */ 214 | /* frame.w = view->frame.local.w * sratio; */ 215 | /* frame.x = x; */ 216 | 217 | /* ku_view_set_frame(vh->hori_v, frame); */ 218 | /* } */ 219 | /* } */ 220 | } 221 | 222 | #endif 223 | -------------------------------------------------------------------------------- /src/kinetic_ui/handler/vh_drag.c: -------------------------------------------------------------------------------- 1 | #ifndef vh_drag_h 2 | #define vh_drag_h 3 | 4 | #include "ku_event.c" 5 | #include "ku_view.c" 6 | 7 | enum vh_drag_event_id 8 | { 9 | VH_DRAG_MOVE, 10 | VH_DRAG_DROP 11 | }; 12 | 13 | typedef struct _vh_drag_t vh_drag_t; 14 | 15 | typedef struct _vh_drag_event_t 16 | { 17 | enum vh_drag_event_id id; 18 | vh_drag_t* vh; 19 | ku_view_t* view; 20 | ku_view_t* dragged_view; 21 | } vh_drag_event_t; 22 | 23 | struct _vh_drag_t 24 | { 25 | void (*on_event)(vh_drag_event_t); 26 | ku_view_t* dragged_view; 27 | }; 28 | 29 | void vh_drag_attach(ku_view_t* view, void (*on_event)(vh_drag_event_t)); 30 | void vh_drag_drag(ku_view_t* view, ku_view_t* item); 31 | 32 | #endif 33 | 34 | #if __INCLUDE_LEVEL__ == 0 35 | 36 | int vh_drag_evt(ku_view_t* view, ku_event_t ev) 37 | { 38 | if (ev.type == KU_EVENT_MOUSE_MOVE && ev.drag) 39 | { 40 | vh_drag_t* vh = view->evt_han_data; 41 | 42 | if (vh->dragged_view) 43 | { 44 | ku_rect_t frame = vh->dragged_view->frame.local; 45 | frame.x = ev.x - frame.w / 2; 46 | frame.y = ev.y - frame.h / 2; 47 | ku_view_set_frame(vh->dragged_view, frame); 48 | 49 | vh_drag_event_t event = {.id = VH_DRAG_MOVE, .vh = vh, .view = view, .dragged_view = vh->dragged_view}; 50 | if (vh->on_event) 51 | (*vh->on_event)(event); 52 | } 53 | } 54 | if (ev.type == KU_EVENT_MOUSE_UP && ev.drag) 55 | { 56 | vh_drag_t* vh = view->evt_han_data; 57 | 58 | if (vh->dragged_view) 59 | { 60 | vh_drag_event_t event = {.id = VH_DRAG_DROP, .vh = vh, .view = view, .dragged_view = vh->dragged_view}; 61 | if (vh->on_event) 62 | (*vh->on_event)(event); 63 | 64 | REL(vh->dragged_view); 65 | vh->dragged_view = NULL; 66 | } 67 | } 68 | 69 | return 1; 70 | } 71 | 72 | void vh_drag_del(void* p) 73 | { 74 | vh_drag_t* vh = p; 75 | 76 | if (vh->dragged_view) REL(vh->dragged_view); 77 | } 78 | 79 | void vh_drag_desc(void* p, int level) 80 | { 81 | } 82 | 83 | void vh_drag_attach(ku_view_t* view, void (*on_event)(vh_drag_event_t)) 84 | { 85 | assert(view->evt_han == NULL && view->evt_han_data == NULL); 86 | 87 | vh_drag_t* vh = CAL(sizeof(vh_drag_t), vh_drag_del, vh_drag_desc); 88 | vh->on_event = on_event; 89 | 90 | view->evt_han_data = vh; 91 | view->evt_han = vh_drag_evt; 92 | } 93 | 94 | void vh_drag_drag(ku_view_t* view, ku_view_t* item) 95 | { 96 | vh_drag_t* vh = view->evt_han_data; 97 | 98 | if (vh->dragged_view) 99 | { 100 | REL(vh->dragged_view); 101 | vh->dragged_view = NULL; 102 | } 103 | if (item) 104 | { 105 | vh->dragged_view = RET(item); 106 | } 107 | } 108 | 109 | #endif 110 | -------------------------------------------------------------------------------- /src/kinetic_ui/handler/vh_key.c: -------------------------------------------------------------------------------- 1 | #ifndef vh_key_h 2 | #define vh_key_h 3 | 4 | #include "ku_view.c" 5 | 6 | typedef struct _vh_key_t vh_key_t; 7 | 8 | typedef struct _vh_key_event_t 9 | { 10 | ku_event_t ev; 11 | vh_key_t* vh; 12 | ku_view_t* view; 13 | } vh_key_event_t; 14 | 15 | struct _vh_key_t 16 | { 17 | void (*on_event)(vh_key_event_t event); 18 | }; 19 | 20 | void vh_key_add(ku_view_t* view, void (*on_event)(vh_key_event_t)); 21 | 22 | #endif 23 | 24 | #if __INCLUDE_LEVEL__ == 0 25 | 26 | int vh_key_evt(ku_view_t* view, ku_event_t ev) 27 | { 28 | if (ev.type == KU_EVENT_KEY_DOWN) 29 | { 30 | vh_key_t* vh = view->evt_han_data; 31 | vh_key_event_t event = {.ev = ev, .vh = vh, .view = view}; 32 | if (vh->on_event) 33 | (*vh->on_event)(event); 34 | } 35 | 36 | return 0; 37 | } 38 | 39 | void vh_key_del(void* p) 40 | { 41 | } 42 | 43 | void vh_key_desc(void* p, int level) 44 | { 45 | printf("vh_key"); 46 | } 47 | 48 | void vh_key_add(ku_view_t* view, void (*on_event)(vh_key_event_t)) 49 | { 50 | assert(view->evt_han == NULL && view->evt_han_data == NULL); 51 | 52 | vh_key_t* vh = CAL(sizeof(vh_key_t), vh_key_del, vh_key_desc); 53 | vh->on_event = on_event; 54 | 55 | view->evt_han_data = vh; 56 | view->evt_han = vh_key_evt; 57 | } 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /src/kinetic_ui/handler/vh_knob.c: -------------------------------------------------------------------------------- 1 | #ifndef vh_knob_h 2 | #define vh_knob_h 3 | 4 | #include "ku_view.c" 5 | 6 | void vh_knob_add(ku_view_t* view, void (*ratio_changed)(ku_view_t* view, float ratio)); 7 | 8 | #endif 9 | 10 | #if __INCLUDE_LEVEL__ == 0 11 | 12 | #include "ku_draw.c" 13 | #include "tg_knob.c" 14 | #include 15 | 16 | typedef struct _vh_knob_t 17 | { 18 | float angle; 19 | char* id; 20 | 21 | void (*ratio_changed)(ku_view_t* view, float ratio); 22 | } vh_knob_t; 23 | 24 | int vh_knob_evt(ku_view_t* view, ku_event_t ev) 25 | { 26 | if (ev.type == KU_EVENT_MOUSE_DOWN || (ev.type == KU_EVENT_MOUSE_MOVE && ev.drag)) 27 | { 28 | vh_knob_t* vh = view->evt_han_data; 29 | 30 | float dx = ev.x - (view->frame.global.x + view->frame.global.w / 2.0); 31 | float dy = ev.y - (view->frame.global.y + view->frame.global.h / 2.0); 32 | float angle = atan2(dy, dx); 33 | float r = sqrt(dx * dx + dy * dy); 34 | 35 | if (angle < 0) 36 | angle += 6.28; 37 | 38 | if (r < view->frame.global.w / 2.0) 39 | { 40 | tg_knob_set_angle(view, angle); 41 | (*vh->ratio_changed)(view, angle); 42 | } 43 | } 44 | else if (ev.type == KU_EVENT_SCROLL) 45 | { 46 | vh_knob_t* vh = view->evt_han_data; 47 | tg_knob_t* tg = view->tex_gen_data; 48 | 49 | float angle = tg->angle - ev.dy / 50.0; 50 | 51 | if (angle < 0) 52 | angle += 6.28; 53 | 54 | if (tg->angle < 3 * 3.14 / 2 && tg->angle > 3.14 && angle > 3 * 3.14 / 2) 55 | angle = tg->angle; 56 | if (tg->angle > 3 * 3.14 / 2 && tg->angle < 2 * 3.14 && angle < 3 * 3.14 / 2) 57 | angle = tg->angle; 58 | 59 | if (angle > 6.28) 60 | angle -= 6.28; 61 | tg_knob_set_angle(view, angle); 62 | (*vh->ratio_changed)(view, angle); 63 | } 64 | 65 | return 1; 66 | } 67 | 68 | void vh_knob_desc(void* p, int level) 69 | { 70 | printf("vh_knob"); 71 | } 72 | 73 | void vh_knob_add(ku_view_t* view, void (*ratio_changed)(ku_view_t* view, float ratio)) 74 | { 75 | assert(view->evt_han == NULL && view->evt_han_data == NULL); 76 | 77 | vh_knob_t* vh = CAL(sizeof(vh_knob_t), NULL, vh_knob_desc); 78 | 79 | vh->ratio_changed = ratio_changed; 80 | 81 | view->evt_han_data = vh; 82 | view->evt_han = vh_knob_evt; 83 | } 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /src/kinetic_ui/handler/vh_roll.c: -------------------------------------------------------------------------------- 1 | #ifndef vh_roll_h 2 | #define vh_roll_h 3 | 4 | #include "ku_event.c" 5 | #include "ku_view.c" 6 | 7 | enum vh_roll_event_id 8 | { 9 | VH_ROLL_IN, 10 | VH_ROLL_OUT 11 | }; 12 | 13 | typedef struct _vh_roll_t vh_roll_t; 14 | 15 | typedef struct _vh_roll_event_t 16 | { 17 | enum vh_roll_event_id id; 18 | vh_roll_t* vh; 19 | ku_view_t* view; 20 | } vh_roll_event_t; 21 | 22 | struct _vh_roll_t 23 | { 24 | char active; 25 | void (*on_event)(vh_roll_event_t); 26 | }; 27 | 28 | void vh_roll_add(ku_view_t* view, void (*on_event)(vh_roll_event_t)); 29 | 30 | #endif 31 | 32 | #if __INCLUDE_LEVEL__ == 0 33 | 34 | int vh_roll_evt(ku_view_t* view, ku_event_t ev) 35 | { 36 | if (ev.type == KU_EVENT_MOUSE_MOVE) 37 | { 38 | vh_roll_t* vh = view->evt_han_data; 39 | ku_rect_t frame = view->frame.global; 40 | 41 | if (!vh->active) 42 | { 43 | if (ev.x >= frame.x && 44 | ev.x <= frame.x + frame.w && 45 | ev.y >= frame.y && 46 | ev.y <= frame.y + frame.h) 47 | { 48 | vh->active = 1; 49 | 50 | vh_roll_event_t event = {.id = VH_ROLL_IN, .view = view, .vh = vh}; 51 | if (vh->on_event) 52 | (*vh->on_event)(event); 53 | } 54 | } 55 | } 56 | else if (ev.type == KU_EVENT_MOUSE_MOVE_OUT) 57 | { 58 | vh_roll_t* vh = view->evt_han_data; 59 | ku_rect_t frame = view->frame.global; 60 | 61 | if (vh->active) 62 | { 63 | if (ev.x < frame.x || 64 | ev.x > frame.x + frame.w || 65 | ev.y < frame.y || 66 | ev.y > frame.y + frame.h) 67 | { 68 | vh->active = 0; 69 | vh_roll_event_t event = {.id = VH_ROLL_OUT, .view = view, .vh = vh}; 70 | if (vh->on_event) 71 | (*vh->on_event)(event); 72 | } 73 | } 74 | } 75 | 76 | return 1; 77 | } 78 | 79 | void vh_roll_del(void* p) 80 | { 81 | } 82 | 83 | void vh_roll_desc(void* p, int level) 84 | { 85 | printf("vh_roll"); 86 | } 87 | 88 | void vh_roll_add(ku_view_t* view, void (*on_event)(vh_roll_event_t)) 89 | { 90 | assert(view->evt_han == NULL && view->evt_han_data == NULL); 91 | 92 | vh_roll_t* vh = CAL(sizeof(vh_roll_t), vh_roll_del, vh_roll_desc); 93 | vh->on_event = on_event; 94 | 95 | view->evt_han_data = vh; 96 | view->evt_han = vh_roll_evt; 97 | } 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /src/kinetic_ui/handler/vh_slider.c: -------------------------------------------------------------------------------- 1 | #ifndef vh_slider_h 2 | #define vh_slider_h 3 | 4 | #include "ku_view.c" 5 | 6 | typedef struct _vh_slider_t vh_slider_t; 7 | 8 | typedef struct _vh_slider_event_t 9 | { 10 | vh_slider_t* vh; 11 | ku_view_t* view; 12 | float ratio; 13 | } vh_slider_event_t; 14 | 15 | struct _vh_slider_t 16 | { 17 | float ratio; 18 | char enabled; 19 | void (*on_event)(vh_slider_event_t); 20 | }; 21 | 22 | void vh_slider_add(ku_view_t* view, void (*on_event)(vh_slider_event_t)); 23 | void vh_slider_set(ku_view_t* view, float ratio); 24 | float vh_slider_get_ratio(ku_view_t* view); 25 | void vh_slider_set_enabled(ku_view_t* view, int flag); 26 | 27 | #endif 28 | 29 | #if __INCLUDE_LEVEL__ == 0 30 | 31 | #include "vh_anim.c" 32 | #include 33 | 34 | int vh_slider_evt(ku_view_t* view, ku_event_t ev) 35 | { 36 | vh_slider_t* vh = view->evt_han_data; 37 | 38 | if (vh->enabled) 39 | { 40 | if (ev.type == KU_EVENT_MOUSE_DOWN || (ev.type == KU_EVENT_MOUSE_MOVE && ev.drag)) 41 | { 42 | float dx = ev.x - view->frame.global.x; 43 | vh->ratio = dx / view->frame.global.w; 44 | 45 | ku_view_t* bar = view->views->data[0]; 46 | ku_rect_t frame = bar->frame.local; 47 | frame.w = dx; 48 | ku_view_set_frame(bar, frame); 49 | 50 | vh_slider_event_t event = {.view = view, .ratio = vh->ratio, .vh = vh}; 51 | if (vh->on_event) 52 | (*vh->on_event)(event); 53 | } 54 | else if (ev.type == KU_EVENT_SCROLL) 55 | { 56 | float ratio = vh->ratio - ev.dx / 50.0; 57 | 58 | if (ratio < 0) 59 | ratio = 0; 60 | if (ratio > 1) 61 | ratio = 1; 62 | 63 | vh->ratio = ratio; 64 | ku_view_t* bar = view->views->data[0]; 65 | ku_rect_t frame = bar->frame.local; 66 | frame.w = view->frame.global.w * vh->ratio; 67 | ku_view_set_frame(bar, frame); 68 | 69 | vh_slider_event_t event = {.view = view, .ratio = vh->ratio, .vh = vh}; 70 | if (vh->on_event) 71 | (*vh->on_event)(event); 72 | } 73 | } 74 | 75 | return 0; 76 | } 77 | 78 | void vh_slider_set(ku_view_t* view, float ratio) 79 | { 80 | vh_slider_t* vh = view->evt_han_data; 81 | vh->ratio = ratio; 82 | ku_view_t* bar = view->views->data[0]; 83 | ku_rect_t frame = bar->frame.local; 84 | frame.w = view->frame.global.w * vh->ratio; 85 | ku_view_set_frame(bar, frame); 86 | } 87 | 88 | float vh_slider_get_ratio(ku_view_t* view) 89 | { 90 | vh_slider_t* vh = view->evt_han_data; 91 | return vh->ratio; 92 | } 93 | 94 | void vh_slider_desc(void* p, int level) 95 | { 96 | printf("vh_slider"); 97 | } 98 | 99 | void vh_slider_del(void* p) 100 | { 101 | } 102 | 103 | void vh_slider_add(ku_view_t* view, void (*on_event)(vh_slider_event_t)) 104 | { 105 | assert(view->evt_han == NULL && view->evt_han_data == NULL); 106 | 107 | vh_slider_t* vh = CAL(sizeof(vh_slider_t), vh_slider_del, vh_slider_desc); 108 | vh->on_event = on_event; 109 | vh->enabled = 1; 110 | 111 | view->evt_han_data = vh; 112 | view->evt_han = vh_slider_evt; 113 | 114 | ku_view_t* bar = view->views->data[0]; 115 | vh_anim_add(bar, NULL, NULL); 116 | } 117 | 118 | void vh_slider_set_enabled(ku_view_t* view, int flag) 119 | { 120 | vh_slider_t* vh = view->evt_han_data; 121 | 122 | if (flag) 123 | { 124 | if (vh->enabled == 0) 125 | { 126 | ku_view_t* bar = view->views->data[0]; 127 | vh_anim_alpha(bar, 0.3, 1.0, 10, AT_LINEAR); 128 | } 129 | } 130 | else 131 | { 132 | if (vh->enabled == 1) 133 | { 134 | ku_view_t* bar = view->views->data[0]; 135 | vh_anim_alpha(bar, 1.0, 0.3, 10, AT_LINEAR); 136 | } 137 | } 138 | 139 | vh->enabled = flag; 140 | } 141 | 142 | #endif 143 | -------------------------------------------------------------------------------- /src/kinetic_ui/handler/vh_touch.c: -------------------------------------------------------------------------------- 1 | #ifndef vh_touch_h 2 | #define vh_touch_h 3 | 4 | #include "ku_view.c" 5 | 6 | typedef struct _vh_touch_t vh_touch_t; 7 | 8 | enum vh_touch_event_id 9 | { 10 | VH_TOUCH_EVENT 11 | }; 12 | 13 | typedef struct _vh_touch_event_t 14 | { 15 | enum vh_touch_event_id id; 16 | vh_touch_t* vh; 17 | ku_view_t* view; 18 | } vh_touch_event_t; 19 | 20 | struct _vh_touch_t 21 | { 22 | void (*on_event)(vh_touch_event_t); 23 | }; 24 | 25 | void vh_touch_add(ku_view_t* view, void (*on_event)(vh_touch_event_t)); 26 | 27 | #endif 28 | 29 | #if __INCLUDE_LEVEL__ == 0 30 | 31 | #include "ku_event.c" 32 | 33 | int vh_touch_evt(ku_view_t* view, ku_event_t ev) 34 | { 35 | if (ev.type == KU_EVENT_MOUSE_DOWN) 36 | { 37 | vh_touch_t* vh = view->evt_han_data; 38 | vh_touch_event_t event = {.id = VH_TOUCH_EVENT, .vh = vh, .view = view}; 39 | if (vh->on_event) 40 | (*vh->on_event)(event); 41 | } 42 | 43 | return 0; 44 | } 45 | 46 | void vh_touch_del(void* p) 47 | { 48 | /* vh_touch_t* vh = p; */ 49 | } 50 | 51 | void vh_touch_desc(void* p, int level) 52 | { 53 | printf("vh_touch"); 54 | } 55 | 56 | void vh_touch_add(ku_view_t* view, void (*on_event)(vh_touch_event_t)) 57 | { 58 | assert(view->evt_han == NULL && view->evt_han_data == NULL); 59 | 60 | vh_touch_t* vh = CAL(sizeof(vh_touch_t), vh_touch_del, vh_touch_desc); 61 | vh->on_event = on_event; 62 | 63 | view->evt_han = vh_touch_evt; 64 | view->evt_han_data = vh; 65 | } 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /src/kinetic_ui/ku_css.c: -------------------------------------------------------------------------------- 1 | /* 2 | Kinetic UI CSS parser 3 | Does pretty dumb parsing, error handling should be improved 4 | */ 5 | 6 | #ifndef ku_css_h 7 | #define ku_css_h 8 | 9 | /* TODO write tests */ 10 | 11 | #include "mt_log.c" 12 | #include "mt_map.c" 13 | #include "mt_string.c" 14 | #include "mt_vector.c" 15 | #include 16 | #include 17 | #include 18 | 19 | typedef struct _css_range_t 20 | { 21 | uint32_t pos; 22 | uint32_t len; 23 | } css_range_t; 24 | 25 | typedef struct _prop_t 26 | { 27 | css_range_t class; 28 | css_range_t key; 29 | css_range_t value; 30 | } prop_t; 31 | 32 | mt_map_t* ku_css_new(char* path); 33 | 34 | #endif 35 | 36 | #if __INCLUDE_LEVEL__ == 0 37 | 38 | #include "mt_string_ext.c" 39 | 40 | uint32_t ku_css_count_props(char* css) 41 | { 42 | int t = 0; // tag index 43 | char* c = css; 44 | while (*c) 45 | { 46 | if (*c == ':') 47 | t++; 48 | c++; 49 | } 50 | return t; 51 | } 52 | 53 | void ku_css_analyze_classes(char* css, prop_t* props) 54 | { 55 | int start = -1; 56 | // char in_l = 0; // in line 57 | uint32_t index = 0; 58 | css_range_t class = {0}; 59 | int in_str = 0; 60 | char* c = css; 61 | while (*c) 62 | { 63 | if (*c == '}' || *c == ' ' || *c == '\r' || *c == '\n') 64 | { 65 | if (c - css - 1 == start) start = c - css; // skip starting empty chars 66 | } 67 | else if (*c == '"') // class name 68 | { 69 | in_str = 1 - in_str; 70 | } 71 | else if (*c == '{') // class name 72 | { 73 | class.pos = start + 1; 74 | class.len = c - css - start - 2; 75 | while (*(css + class.pos + class.len) == ' ') class.len--; 76 | class.len++; 77 | start = c - css; 78 | } 79 | else if (*c == ':' && !in_str) // property name 80 | { 81 | props[index].class = class; 82 | props[index].key.pos = start + 1; 83 | props[index].key.len = c - css - start - 1; 84 | start = c - css; 85 | } 86 | else if (*c == ';') // value name 87 | { 88 | props[index].class = class; 89 | props[index].value.pos = start + 1; 90 | props[index].value.len = c - css - start - 1; 91 | 92 | start = c - css; 93 | index++; 94 | } 95 | 96 | c++; 97 | } 98 | } 99 | 100 | void ku_css_prop_desc(void* p, int level) 101 | { 102 | printf("html prop_t"); 103 | } 104 | 105 | prop_t* ku_css_new_parse(char* css) 106 | { 107 | uint32_t cnt = ku_css_count_props(css); 108 | prop_t* props = CAL(sizeof(prop_t) * (cnt + 1), NULL, ku_css_prop_desc); // REL 1 109 | 110 | ku_css_analyze_classes(css, props); 111 | 112 | for (uint32_t i = 0; i < cnt; i++) 113 | { 114 | // prop_t p = props[i]; 115 | // printf("extracted prop %.*s %.*s %.*s\n", p.class.len, css + p.class.pos, p.key.len, css + p.key.pos, p.value.len, css + p.value.pos); 116 | } 117 | 118 | return props; 119 | } 120 | 121 | mt_map_t* ku_css_new(char* filepath) 122 | { 123 | mt_map_t* styles = MNEW(); // REL 2 124 | char* css = mt_string_new_file(filepath); // REL 0 125 | 126 | if (css) 127 | { 128 | prop_t* view_styles = ku_css_new_parse(css); // REL 1 129 | prop_t* props = view_styles; 130 | 131 | while ((*props).class.len > 0) 132 | { 133 | prop_t t = *props; 134 | char* cls = CAL(sizeof(char) * t.class.len + 1, NULL, mt_string_describe); // REL 3 135 | char* key = CAL(sizeof(char) * t.key.len + 1, NULL, mt_string_describe); // REL 4 136 | char* val = CAL(sizeof(char) * t.value.len + 1, NULL, mt_string_describe); // REL 5 137 | 138 | memcpy(cls, css + t.class.pos, t.class.len); 139 | memcpy(key, css + t.key.pos, t.key.len); 140 | memcpy(val, css + t.value.pos, t.value.len); 141 | 142 | mt_map_t* style = MGET(styles, cls); 143 | if (style == NULL) 144 | { 145 | style = MNEW(); // REL 6 146 | MPUT(styles, cls, style); 147 | REL(style); // REL 6 148 | } 149 | MPUT(style, key, val); 150 | props += 1; 151 | REL(cls); // REL 3 152 | REL(key); // REL 4 153 | REL(val); // REL 5 154 | } 155 | 156 | REL(view_styles); 157 | REL(css); 158 | } 159 | else mt_log_error("Empty CSS descriptor"); 160 | 161 | return styles; 162 | } 163 | 164 | #endif 165 | -------------------------------------------------------------------------------- /src/kinetic_ui/ku_event.c: -------------------------------------------------------------------------------- 1 | #ifndef ku_event_h 2 | #define ku_event_h 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | enum evtype 9 | { 10 | KU_EVENT_EMPTY, 11 | KU_EVENT_FRAME, 12 | KU_EVENT_TIME, 13 | KU_EVENT_RESIZE, 14 | KU_EVENT_MOUSE_MOVE, 15 | KU_EVENT_MOUSE_DOWN, 16 | KU_EVENT_MOUSE_UP, 17 | KU_EVENT_MOUSE_MOVE_OUT, 18 | KU_EVENT_MOUSE_DOWN_OUT, 19 | KU_EVENT_MOUSE_UP_OUT, 20 | KU_EVENT_SCROLL, 21 | KU_EVENT_SCROLL_X_END, 22 | KU_EVENT_SCROLL_Y_END, 23 | KU_EVENT_KEY_DOWN, 24 | KU_EVENT_KEY_UP, 25 | KU_EVENT_TEXT, 26 | KU_EVENT_WINDOW_SHOWN, 27 | KU_EVENT_PINCH, 28 | KU_EVENT_HOLD_START, 29 | KU_EVENT_HOLD_END, 30 | KU_EVENT_STDIN, 31 | KU_EVENT_FOCUS, 32 | KU_EVENT_UNFOCUS, 33 | }; 34 | 35 | typedef struct _ku_event_t 36 | { 37 | int type; 38 | 39 | /* poiniter properties */ 40 | 41 | int x; // mouse coord x 42 | int y; // mouse coord y 43 | 44 | /* resize */ 45 | 46 | int w; // resize width 47 | int h; // resize height 48 | 49 | /* scroll */ 50 | 51 | float dx; // scroll x 52 | float dy; // scroll y 53 | 54 | /* pinch */ 55 | 56 | float ratio; // pinch ratio 57 | 58 | /* mouse */ 59 | 60 | int drag; // mouse drag 61 | int dclick; // double click 62 | int button; // mouse button id 63 | 64 | /* time */ 65 | 66 | uint32_t time; // milliseconds since start 67 | struct timespec time_unix; // unix timestamp 68 | float time_frame; // elapsed time since last frame 69 | uint32_t frame; // actual frame count 70 | 71 | /* keyboard */ 72 | 73 | uint32_t keycode; 74 | int repeat; // key event is coming from repeat 75 | 76 | int ctrl_down; // modifiers 77 | int shift_down; // modifiers 78 | 79 | char text[8]; 80 | 81 | /* window */ 82 | 83 | void* window; 84 | 85 | } ku_event_t; 86 | 87 | void ku_event_write(FILE* file, ku_event_t ev); 88 | ku_event_t ku_event_read(FILE* file); 89 | 90 | #endif 91 | 92 | #if __INCLUDE_LEVEL__ == 0 93 | 94 | #include "mt_log.c" 95 | 96 | /* frame type x y w h dx dy ratio drag dclick button time time_frame keycode repeat ctrl_down shift_down text */ 97 | char* ku_print_format = "%i %i %i %i %i %i %f %f %f %i %i %i %u %f %u %i %i %i '%s'\n"; 98 | char* ku_scan_format = "%i %i %i %i %i %i %f %f %f %i %i %i %u %f %u %i %i %i '%[^']'\n"; 99 | 100 | void ku_event_write(FILE* file, ku_event_t ev) 101 | { 102 | fprintf( 103 | file, 104 | ku_print_format, 105 | ev.frame, 106 | ev.type, 107 | ev.x, 108 | ev.y, 109 | ev.w, 110 | ev.h, 111 | ev.dx, 112 | ev.dy, 113 | ev.ratio, 114 | ev.drag, 115 | ev.dclick, 116 | ev.button, 117 | ev.time, 118 | ev.time_frame, 119 | ev.keycode, 120 | ev.repeat, 121 | ev.ctrl_down, 122 | ev.shift_down, 123 | ev.text[0] == '\0' ? "T" : ev.text); 124 | } 125 | 126 | ku_event_t ku_event_read(FILE* file) 127 | { 128 | ku_event_t ev = {0}; 129 | int res = fscanf( 130 | file, 131 | ku_scan_format, 132 | &ev.frame, 133 | &ev.type, 134 | &ev.x, 135 | &ev.y, 136 | &ev.w, 137 | &ev.h, 138 | &ev.dx, 139 | &ev.dy, 140 | &ev.ratio, 141 | &ev.drag, 142 | &ev.dclick, 143 | &ev.button, 144 | &ev.time, 145 | &ev.time_frame, 146 | &ev.keycode, 147 | &ev.repeat, 148 | &ev.ctrl_down, 149 | &ev.shift_down, 150 | &ev.text); 151 | 152 | if (res < 0) 153 | mt_log_error("Couldn't scanf file"); 154 | 155 | return ev; 156 | } 157 | 158 | #endif 159 | -------------------------------------------------------------------------------- /src/kinetic_ui/ku_fontconfig.c: -------------------------------------------------------------------------------- 1 | #ifndef ku_fontconfig_h 2 | #define ku_fontconfig_h 3 | 4 | char* ku_fontconfig_path(char* face_desc); 5 | void ku_fontconfig_delete(); 6 | 7 | #endif 8 | 9 | #if __INCLUDE_LEVEL__ == 0 10 | 11 | #include 12 | #ifdef __linux__ 13 | #include 14 | #endif 15 | 16 | // #define _POSIX_C_SOURCE 200112L 17 | #include "mt_map.c" 18 | #include "mt_memory.c" 19 | #include "mt_string.c" 20 | #include 21 | #include 22 | 23 | mt_map_t* ku_fontconfig_cache = NULL; 24 | 25 | char* ku_fontconfig_path(char* face_desc) 26 | { 27 | char* filename = NULL; 28 | if (face_desc) 29 | { 30 | if (ku_fontconfig_cache == NULL) 31 | ku_fontconfig_cache = MNEW(); 32 | filename = MGET(ku_fontconfig_cache, face_desc); 33 | 34 | if (filename == NULL) 35 | { 36 | char buff[PATH_MAX]; 37 | filename = mt_string_new_cstring(""); // REL 0 38 | char* command = mt_string_new_format(80, "fc-match \"%s\" --format=%%{file}", face_desc); // REL 1 39 | FILE* pipe = popen(command, "r"); // CLOSE 0 40 | while (fgets(buff, sizeof(buff), pipe) != NULL) filename = mt_string_append(filename, buff); 41 | pclose(pipe); // CLOSE 0 42 | REL(command); // REL 1 43 | 44 | MPUTR(ku_fontconfig_cache, face_desc, filename); 45 | } 46 | } 47 | return filename; 48 | } 49 | 50 | void ku_fontconfig_delete() 51 | { 52 | if (ku_fontconfig_cache) REL(ku_fontconfig_cache); 53 | ku_fontconfig_cache = NULL; 54 | } 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/kinetic_ui/ku_gen_html.c: -------------------------------------------------------------------------------- 1 | #ifndef ku_gen_html_h 2 | #define ku_gen_html_h 3 | 4 | #include "mt_vector.c" 5 | 6 | void ku_gen_html_parse(char* htmlpath, mt_vector_t* views); 7 | 8 | #endif 9 | 10 | #if __INCLUDE_LEVEL__ == 0 11 | 12 | #include "ku_html.c" 13 | #include "ku_view.c" 14 | #include "mt_log.c" 15 | #include "mt_string_ext.c" 16 | 17 | void ku_gen_html_parse(char* htmlpath, mt_vector_t* views) 18 | { 19 | char* html = mt_string_new_file(htmlpath); // REL 0 20 | 21 | if (html != NULL) 22 | { 23 | tag_t* tags = ku_html_new(html); // REL 1 24 | tag_t* head = tags; 25 | 26 | while ((*tags).len > 0) 27 | { 28 | tag_t t = *tags; 29 | if (t.id.len > 0) 30 | { 31 | // extract id 32 | char* id = CAL(sizeof(char) * t.id.len + 1, NULL, mt_string_describe); // REL 0 33 | memcpy(id, html + t.id.pos + 1, t.id.len); 34 | ku_view_t* view = ku_view_new(id, (ku_rect_t){0}); // REL 1 35 | 36 | if (t.level > 0) 37 | { 38 | // add to parent 39 | ku_view_t* parent = views->data[t.parent]; 40 | ku_view_add_subview(parent, view); 41 | } 42 | 43 | if (t.class.len > 0) 44 | { 45 | // store css classes 46 | char* class = CAL(sizeof(char) * t.class.len + 1, NULL, mt_string_describe); // REL 0 47 | memcpy(class, html + t.class.pos + 1, t.class.len); 48 | ku_view_set_class(view, class); 49 | REL(class); 50 | } 51 | 52 | if (t.type.len > 0) 53 | { 54 | // store html stype 55 | char* type = CAL(sizeof(char) * t.type.len + 1, NULL, mt_string_describe); // REL 2 56 | memcpy(type, html + t.type.pos + 1, t.type.len); 57 | ku_view_set_type(view, type); 58 | REL(type); // REL 2 59 | } 60 | 61 | if (t.text.len > 0) 62 | { 63 | // store html stype 64 | char* text = CAL(sizeof(char) * t.text.len + 1, NULL, mt_string_describe); // REL 2 65 | memcpy(text, html + t.text.pos + 1, t.text.len); 66 | ku_view_set_text(view, text); 67 | REL(text); // REL 2 68 | } 69 | 70 | if (t.script.len > 0) 71 | { 72 | // store html stype 73 | char* script = CAL(sizeof(char) * t.script.len + 1, NULL, mt_string_describe); // REL 2 74 | memcpy(script, html + t.script.pos + 1, t.script.len); 75 | ku_view_set_script(view, script); 76 | REL(script); // REL 2 77 | } 78 | 79 | VADD(views, view); 80 | 81 | REL(id); // REL 0 82 | REL(view); // REL 1 83 | } 84 | else 85 | { 86 | static int divcnt = 0; 87 | char* divid = mt_string_new_format(10, "div%i", divcnt++); 88 | // idless view, probably
89 | ku_view_t* view = ku_view_new(divid, (ku_rect_t){0}); 90 | VADD(views, view); 91 | REL(view); 92 | REL(divid); 93 | } 94 | tags += 1; 95 | } 96 | 97 | // cleanup 98 | 99 | REL(head); // REL 1 100 | REL(html); // REL 0 101 | } 102 | else mt_log_error("No HTML description"); 103 | } 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /src/kinetic_ui/ku_gen_textstyle.c: -------------------------------------------------------------------------------- 1 | #ifndef ku_gen_textstyle_h 2 | #define ku_gen_textstyle_h 3 | 4 | #include "ku_text.c" 5 | #include "ku_view.c" 6 | 7 | textstyle_t ku_gen_textstyle_parse(ku_view_t* view); 8 | 9 | #endif 10 | 11 | #if __INCLUDE_LEVEL__ == 0 12 | 13 | #include "ku_fontconfig.c" 14 | #include 15 | 16 | textstyle_t ku_gen_textstyle_parse(ku_view_t* view) 17 | { 18 | textstyle_t style = {0}; 19 | 20 | char* font = ku_fontconfig_path(view->style.font_family); 21 | if (font) strcpy(style.font, font); 22 | 23 | style.size = view->style.font_size > 0 ? view->style.font_size : 15; 24 | 25 | style.align = view->style.text_align; 26 | style.valign = view->style.vertical_align; 27 | /* style.autosize = */ 28 | style.multiline = view->style.word_wrap == 1; 29 | style.line_height = view->style.line_height; 30 | 31 | style.margin = view->style.margin; 32 | if (view->style.margin_left < INT_MAX) style.margin_left = view->style.margin_left; 33 | if (view->style.margin_right < INT_MAX) style.margin_right = view->style.margin_right; 34 | if (view->style.margin_top < INT_MAX) style.margin_top = view->style.margin_top; 35 | if (view->style.margin_bottom < INT_MAX) style.margin_bottom = view->style.margin_bottom; 36 | 37 | style.textcolor = view->style.color; 38 | style.backcolor = view->style.background_color; 39 | 40 | return style; 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /src/kinetic_ui/ku_gen_type.c: -------------------------------------------------------------------------------- 1 | #ifndef ku_gen_type_h 2 | #define ku_gen_type_h 3 | 4 | #include "mt_vector.c" 5 | #include "vh_button.c" 6 | #include "vh_slider.c" 7 | 8 | void ku_gen_type_apply(mt_vector_t* views, void (*button_event)(vh_button_event_t), void (*slider_event)(vh_slider_event_t)); 9 | 10 | #endif 11 | 12 | #if __INCLUDE_LEVEL__ == 0 13 | 14 | #include "ku_view.c" 15 | #include "tg_css.c" 16 | #include "tg_text.c" 17 | 18 | void ku_gen_type_apply(mt_vector_t* views, void (*button_event)(vh_button_event_t), void (*slider_event)(vh_slider_event_t)) 19 | { 20 | for (size_t index = 0; index < views->length; index++) 21 | { 22 | ku_view_t* view = views->data[index]; 23 | 24 | if (view->type && strcmp(view->type, "label") == 0) 25 | { 26 | tg_text_add(view); 27 | tg_text_set1(view, view->text); 28 | } 29 | else if (view->style.background_color > 0 || view->style.border_color > 0) 30 | { 31 | tg_css_add(view); 32 | } 33 | else if (strlen(view->style.background_image) > 0) 34 | { 35 | tg_css_add(view); 36 | } 37 | 38 | if (view->type && strcmp(view->type, "button") == 0) 39 | { 40 | vh_button_add(view, VH_BUTTON_NORMAL, button_event); 41 | } 42 | else if (view->type && strcmp(view->type, "slider") == 0) 43 | { 44 | vh_slider_add(view, slider_event); 45 | } 46 | } 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/kinetic_ui/ku_html.c: -------------------------------------------------------------------------------- 1 | #ifndef ku_html_h 2 | #define ku_html_h 3 | 4 | /* TODO write tests */ 5 | 6 | #include "mt_string.c" 7 | #include "mt_vector.c" 8 | #include 9 | #include 10 | #include 11 | 12 | typedef struct _html_range_t 13 | { 14 | uint32_t pos; 15 | uint32_t len; 16 | } html_range_t; 17 | 18 | typedef struct _tag_t 19 | { 20 | uint32_t pos; 21 | uint32_t len; 22 | 23 | uint32_t level; 24 | uint32_t parent; 25 | 26 | html_range_t id; 27 | html_range_t type; 28 | html_range_t text; 29 | html_range_t class; 30 | html_range_t script; 31 | } tag_t; 32 | 33 | tag_t* ku_html_new(char* path); 34 | 35 | #endif 36 | 37 | #if __INCLUDE_LEVEL__ == 0 38 | 39 | uint32_t ku_html_count_tags(char* html) 40 | { 41 | uint32_t t = 0; // tag index 42 | char* c = html; 43 | int in_tag = 0; 44 | int in_comm = 0; 45 | while (*c) 46 | { 47 | if (*c == '<') 48 | { 49 | if (!in_comm) 50 | { 51 | in_tag = 1; 52 | } 53 | } 54 | else if (*c == '!') 55 | { 56 | if (in_tag) 57 | { 58 | if (*(c - 1) == '<') in_comm += 1; 59 | } 60 | } 61 | else if (*c == '>') 62 | { 63 | if (in_comm) 64 | { 65 | if (*(c - 1) == '-') in_comm -= 1; 66 | 67 | if (!in_comm) 68 | { 69 | in_tag = 0; 70 | } 71 | } 72 | else if (in_tag) 73 | { 74 | in_tag = 0; 75 | t++; 76 | } 77 | } 78 | c++; 79 | } 80 | 81 | return t; 82 | } 83 | 84 | void ku_html_extract_tags(char* html, tag_t* tags) 85 | { 86 | uint32_t t = 0; // tag index 87 | uint32_t i = 0; // char index 88 | char* c = html; 89 | int in_tag = 0; 90 | int in_comm = 0; 91 | while (*c) 92 | { 93 | if (*c == '<') 94 | { 95 | if (!in_comm) 96 | { 97 | tags[t].pos = i; 98 | in_tag = 1; 99 | } 100 | } 101 | else if (*c == '!') 102 | { 103 | if (in_tag) 104 | { 105 | if (*(c - 1) == '<') in_comm += 1; 106 | } 107 | } 108 | else if (*c == '>') 109 | { 110 | if (in_comm) 111 | { 112 | if (*(c - 1) == '-') in_comm -= 1; 113 | 114 | if (!in_comm) 115 | { 116 | in_tag = 0; 117 | } 118 | } 119 | else if (in_tag) 120 | { 121 | tags[t].len = i - tags[t].pos + 1; 122 | in_tag = 0; 123 | // printf("storing %i tag %.*s\n", t, tags[t].len, html + tags[t].pos); 124 | t++; 125 | } 126 | } 127 | i++; 128 | c++; 129 | } 130 | } 131 | 132 | html_range_t ku_html_extract_string(char* str, uint32_t pos, uint32_t len) 133 | { 134 | int start = 0; 135 | int end = 0; 136 | int in = 0; 137 | for (uint32_t i = pos; i < pos + len; i++) 138 | { 139 | char c = str[i]; 140 | if (c == '"') 141 | { 142 | if (!in) 143 | { 144 | in = 1; 145 | start = i; 146 | } 147 | else 148 | { 149 | in = 0; 150 | end = i; 151 | break; 152 | } 153 | } 154 | } 155 | if (!in) 156 | return ((html_range_t){.pos = start, .len = end - start - 1}); 157 | else 158 | return ((html_range_t){0}); 159 | } 160 | 161 | html_range_t ku_html_extract_value(tag_t tag, char* key, char* html) 162 | { 163 | char* start = strstr(html + tag.pos, key); 164 | uint32_t len = start - (html + tag.pos); 165 | 166 | if (len < tag.len) 167 | { 168 | html_range_t range = ku_html_extract_string(html, start - html, tag.len); 169 | return range; 170 | } 171 | return ((html_range_t){0}); 172 | } 173 | 174 | void ku_html_analyze_tags(char* html, tag_t* tags, uint32_t count) 175 | { 176 | int l = 0; // level 177 | for (uint32_t i = 0; i < count; i++) 178 | { 179 | tags[i].level = l++; 180 | 181 | int ii = i; 182 | while (ii-- > 0) 183 | { 184 | if (tags[ii].level == tags[i].level - 1) 185 | { 186 | tags[i].parent = ii; 187 | break; 188 | } 189 | } 190 | 191 | tags[i].id = ku_html_extract_value(tags[i], "id=\"", html); 192 | tags[i].type = ku_html_extract_value(tags[i], "type=\"", html); 193 | tags[i].text = ku_html_extract_value(tags[i], "text=\"", html); 194 | tags[i].class = ku_html_extract_value(tags[i], "class=\"", html); 195 | tags[i].script = ku_html_extract_value(tags[i], "script=\"", html); 196 | 197 | // tag_t t = tags[i]; 198 | 199 | if (html[tags[i].pos + 1] == '/') 200 | l -= 2; //
201 | if (html[tags[i].pos + tags[i].len - 2] == '/' || html[tags[i].pos + tags[i].len - 2] == '-') 202 | l -= 1; // /> 203 | } 204 | } 205 | 206 | void ku_html_tag_describe(void* p, int level) 207 | { 208 | printf("html tag_t"); 209 | } 210 | 211 | tag_t* ku_html_new(char* html) 212 | { 213 | uint32_t cnt = ku_html_count_tags(html); 214 | tag_t* tags = CAL(sizeof(tag_t) * (cnt + 1), NULL, ku_html_tag_describe); // REL 0 215 | 216 | ku_html_extract_tags(html, tags); 217 | ku_html_analyze_tags(html, tags, cnt); 218 | 219 | /* for (int i = 0; i < cnt; i++) */ 220 | /* { */ 221 | /* tag_t t = tags[i]; */ 222 | /* printf("ind %i tag %.*s lvl %i par %i\n", i, t.len, html + t.pos, t.level, t.parent); */ 223 | /* } */ 224 | 225 | return tags; 226 | } 227 | 228 | #endif 229 | -------------------------------------------------------------------------------- /src/kinetic_ui/ku_png.c: -------------------------------------------------------------------------------- 1 | #ifndef ku_png_h 2 | #define ku_png_h 3 | 4 | #include "ku_bitmap.c" 5 | #include 6 | 7 | void ku_png_get_size(char* path, int* width, int* height); 8 | void ku_png_load_into(char* path, ku_bitmap_t* bitmap); 9 | void ku_png_write(char* filename, ku_bitmap_t* bitmap); 10 | 11 | #endif 12 | 13 | #if __INCLUDE_LEVEL__ == 0 14 | 15 | #define PNG_DEBUG 3 16 | #include "ku_draw.c" 17 | #include "mt_log.c" 18 | #include "mt_memory.c" 19 | #include 20 | #include 21 | 22 | void ku_png_get_size(char* path, int* width, int* height) 23 | { 24 | unsigned char header[8]; 25 | 26 | /* open file and test for it being a png */ 27 | FILE* fp = fopen(path, "rb"); 28 | 29 | if (fp) 30 | { 31 | int res = fread(header, 1, 8, fp); 32 | if (res == 0) mt_log_error("fread error"); 33 | 34 | if (png_sig_cmp(header, 0, 8) == 0) 35 | { 36 | png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 37 | 38 | if (png_ptr) 39 | { 40 | png_infop info_ptr = png_create_info_struct(png_ptr); 41 | 42 | if (info_ptr) 43 | { 44 | if (setjmp(png_jmpbuf(png_ptr)) == 0) 45 | { 46 | png_init_io(png_ptr, fp); 47 | png_set_sig_bytes(png_ptr, 8); 48 | 49 | png_read_info(png_ptr, info_ptr); 50 | 51 | *width = png_get_image_width(png_ptr, info_ptr); 52 | *height = png_get_image_height(png_ptr, info_ptr); 53 | } 54 | else mt_log_error("png init io failed"); 55 | 56 | png_destroy_info_struct(png_ptr, &info_ptr); 57 | } 58 | else mt_log_error("png_create_info_struct failed"); 59 | 60 | png_destroy_read_struct(&png_ptr, &info_ptr, NULL); 61 | } 62 | else mt_log_error("png_create_read_struct failed"); 63 | } 64 | else mt_log_error("Not a PNG file"); 65 | 66 | fclose(fp); 67 | } 68 | else mt_log_error("Cannot open %s for read", path); 69 | } 70 | 71 | void ku_png_load_into(char* path, ku_bitmap_t* bitmap) 72 | { 73 | unsigned char header[8]; 74 | 75 | /* open file and test for it being a png */ 76 | FILE* fp = fopen(path, "rb"); 77 | 78 | if (fp) 79 | { 80 | int res = fread(header, 1, 8, fp); 81 | if (res == 0) mt_log_error("fread error"); 82 | 83 | if (png_sig_cmp(header, 0, 8) == 0) 84 | { 85 | png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 86 | 87 | if (png_ptr) 88 | { 89 | png_infop info_ptr = png_create_info_struct(png_ptr); 90 | 91 | if (info_ptr) 92 | { 93 | if (setjmp(png_jmpbuf(png_ptr)) == 0) 94 | { 95 | png_init_io(png_ptr, fp); 96 | png_set_sig_bytes(png_ptr, 8); 97 | 98 | png_read_info(png_ptr, info_ptr); 99 | 100 | int width = png_get_image_width(png_ptr, info_ptr); 101 | int height = png_get_image_height(png_ptr, info_ptr); 102 | 103 | png_bytep* row_pointers; 104 | 105 | png_read_update_info(png_ptr, info_ptr); 106 | 107 | /* read file */ 108 | if (setjmp(png_jmpbuf(png_ptr)) == 0) 109 | { 110 | int y; 111 | size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); 112 | 113 | row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height); 114 | 115 | for (y = 0; y < height; y++) row_pointers[y] = (png_byte*) malloc(rowbytes); 116 | 117 | png_read_image(png_ptr, row_pointers); 118 | 119 | ku_bitmap_t* rawbm = ku_bitmap_new(width, height); 120 | 121 | for (y = 0; y < height; y++) memcpy((uint8_t*) rawbm->data + y * width * 4, row_pointers[y], rowbytes); 122 | 123 | for (y = 0; y < height; y++) free(row_pointers[y]); 124 | free(row_pointers); 125 | 126 | if (bitmap->w == rawbm->w && bitmap->h == rawbm->h) 127 | ku_draw_insert(bitmap, rawbm, 0, 0); 128 | else 129 | ku_draw_scale(rawbm, bitmap); 130 | 131 | REL(rawbm); 132 | } 133 | else mt_log_error("Cannot read PNG"); 134 | } 135 | else mt_log_error("png init io failed"); 136 | 137 | png_destroy_info_struct(png_ptr, &info_ptr); 138 | } 139 | else mt_log_error("png_create_info_struct failed"); 140 | 141 | png_destroy_read_struct(&png_ptr, &info_ptr, NULL); 142 | } 143 | else mt_log_error("png_create_read_struct failed"); 144 | } 145 | else mt_log_error("Not a PNG file"); 146 | 147 | fclose(fp); 148 | } 149 | else mt_log_error("Cannot open %s for read", path); 150 | } 151 | 152 | void ku_png_write(char* filename, ku_bitmap_t* bitmap) 153 | { 154 | int y; 155 | 156 | FILE* fp = fopen(filename, "wb"); 157 | 158 | if (fp) 159 | { 160 | png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 161 | 162 | if (png_ptr) 163 | { 164 | png_infop info_ptr = png_create_info_struct(png_ptr); 165 | 166 | if (info_ptr) 167 | { 168 | if (!setjmp(png_jmpbuf(png_ptr))) 169 | { 170 | png_init_io(png_ptr, fp); 171 | 172 | png_set_IHDR( 173 | png_ptr, 174 | info_ptr, 175 | bitmap->w, 176 | bitmap->h, 177 | 8, 178 | PNG_COLOR_TYPE_RGBA, 179 | PNG_INTERLACE_NONE, 180 | PNG_COMPRESSION_TYPE_DEFAULT, 181 | PNG_FILTER_TYPE_DEFAULT); 182 | png_write_info(png_ptr, info_ptr); 183 | 184 | size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); 185 | 186 | png_bytep* row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * bitmap->h); 187 | 188 | for (y = 0; y < bitmap->h; y++) row_pointers[y] = (png_byte*) malloc(rowbytes); 189 | 190 | for (y = 0; y < bitmap->h; y++) memcpy(row_pointers[y], (uint8_t*) bitmap->data + y * bitmap->w * 4, rowbytes); 191 | 192 | if (!row_pointers) abort(); 193 | 194 | png_write_image(png_ptr, row_pointers); 195 | png_write_end(png_ptr, NULL); 196 | 197 | for (y = 0; y < bitmap->h; y++) free(row_pointers[y]); 198 | free(row_pointers); 199 | } 200 | else mt_log_error("cannot set jump"); 201 | } 202 | else mt_log_error("Cannot create info struct"); 203 | 204 | png_destroy_write_struct(&png_ptr, &info_ptr); 205 | } 206 | else mt_log_error("png create write failed"); 207 | 208 | fclose(fp); 209 | } 210 | else mt_log_error("Cannot open %s for read", filename); 211 | } 212 | 213 | #endif 214 | -------------------------------------------------------------------------------- /src/kinetic_ui/ku_recorder.c: -------------------------------------------------------------------------------- 1 | #ifndef ku_recorder_h 2 | #define ku_recorder_h 3 | 4 | #include "ku_event.c" 5 | 6 | void ku_recorder_init(void (*update)(ku_event_t)); 7 | void ku_recorder_destroy(); 8 | void ku_recorder_update(ku_event_t ev); 9 | void ku_recorder_record(char* path); 10 | void ku_recorder_replay(char* path); 11 | 12 | #endif 13 | 14 | #if __INCLUDE_LEVEL__ == 0 15 | 16 | #include "mt_vector.c" 17 | #include 18 | 19 | enum ku_recorder_mode_t 20 | { 21 | KU_REC_MODE_NORMAL, 22 | KU_REC_MODE_RECORD, 23 | KU_REC_MODE_REPLAY, 24 | }; 25 | 26 | struct ku_recorder_t 27 | { 28 | size_t index; 29 | FILE* file; 30 | mt_vector_t* eventqueue; 31 | void (*update)(ku_event_t); 32 | enum ku_recorder_mode_t mode; 33 | } kurec; 34 | 35 | void ku_recorder_init(void (*update)(ku_event_t)) 36 | { 37 | kurec.mode = KU_REC_MODE_NORMAL; 38 | kurec.update = update; 39 | kurec.eventqueue = VNEW(); 40 | } 41 | 42 | void ku_recorder_record(char* path) 43 | { 44 | kurec.mode = KU_REC_MODE_RECORD; 45 | FILE* file = fopen(path, "w"); 46 | if (!file) printf("evrec recorder : cannot open file %s\n", path); 47 | kurec.file = file; 48 | } 49 | 50 | void ku_recorder_replay(char* path) 51 | { 52 | kurec.mode = KU_REC_MODE_REPLAY; 53 | FILE* file = fopen(path, "r"); 54 | if (!file) 55 | printf("evrec player : cannot open file %s\n", path); 56 | 57 | kurec.file = file; 58 | 59 | while (1) 60 | { 61 | ku_event_t ev = ku_event_read(file); 62 | VADDR(kurec.eventqueue, HEAP(ev)); 63 | if (feof(file)) 64 | break; 65 | } 66 | 67 | printf("%li events read\n", kurec.eventqueue->length); 68 | } 69 | 70 | void ku_recorder_destroy() 71 | { 72 | if (kurec.file) fclose(kurec.file); 73 | if (kurec.eventqueue) REL(kurec.eventqueue); 74 | } 75 | 76 | void ku_recorder_update_record(ku_event_t ev) 77 | { 78 | /* normalize floats for deterministic movements during record/replay */ 79 | ev.dx = floor(ev.dx * 10000) / 10000; 80 | ev.dy = floor(ev.dy * 10000) / 10000; 81 | ev.ratio = floor(ev.ratio * 10000) / 10000; 82 | ev.time_frame = floor(ev.time_frame * 10000) / 10000; 83 | 84 | if (ev.type == KU_EVENT_FRAME || ev.type == KU_EVENT_TIME || ev.type == KU_EVENT_WINDOW_SHOWN) 85 | { 86 | /* record and send waiting events */ 87 | for (size_t index = 0; index < kurec.eventqueue->length; index++) 88 | { 89 | ku_event_t* event = (ku_event_t*) kurec.eventqueue->data[index]; 90 | event->frame = ev.frame; 91 | 92 | ku_event_write(kurec.file, *event); 93 | 94 | (*kurec.update)(*event); 95 | } 96 | 97 | mt_vector_reset(kurec.eventqueue); 98 | 99 | /* send frame event */ 100 | (*kurec.update)(ev); 101 | } 102 | else 103 | { 104 | /* queue event */ 105 | void* event = HEAP(ev); 106 | VADDR(kurec.eventqueue, event); 107 | } 108 | } 109 | 110 | void ku_recorder_update_replay(ku_event_t ev) 111 | { 112 | if (ev.type == KU_EVENT_FRAME || ev.type == KU_EVENT_WINDOW_SHOWN) 113 | { 114 | while (kurec.index < kurec.eventqueue->length) 115 | { 116 | ku_event_t* event = kurec.eventqueue->data[kurec.index]; 117 | 118 | if (event->frame < ev.frame) 119 | { 120 | kurec.index++; 121 | (*kurec.update)(*event); 122 | } 123 | else break; 124 | } 125 | 126 | (*kurec.update)(ev); 127 | } 128 | } 129 | 130 | void ku_recorder_update(ku_event_t ev) 131 | { 132 | if (kurec.mode == KU_REC_MODE_NORMAL) (*kurec.update)(ev); 133 | else if (kurec.mode == KU_REC_MODE_RECORD) ku_recorder_update_record(ev); 134 | else if (kurec.mode == KU_REC_MODE_REPLAY) ku_recorder_update_replay(ev); 135 | } 136 | 137 | #endif 138 | -------------------------------------------------------------------------------- /src/kinetic_ui/ku_rect.c: -------------------------------------------------------------------------------- 1 | #ifndef ku_rect_h 2 | #define ku_rect_h 3 | 4 | /* TODO write tests */ 5 | 6 | typedef struct _ku_rect_t ku_rect_t; 7 | struct _ku_rect_t 8 | { 9 | float x; 10 | float y; 11 | float w; 12 | float h; 13 | }; 14 | 15 | int ku_rect_equals(ku_rect_t r1, ku_rect_t r2); 16 | ku_rect_t ku_rect_add(ku_rect_t r1, ku_rect_t r2); 17 | ku_rect_t ku_rect_is(ku_rect_t l, ku_rect_t r); 18 | void ku_rect_describe(ku_rect_t rect); 19 | 20 | #endif 21 | 22 | #if __INCLUDE_LEVEL__ == 0 23 | 24 | #include 25 | 26 | #define VMIN(X, Y) (((X) < (Y)) ? (X) : (Y)) 27 | #define VMAX(X, Y) (((X) > (Y)) ? (X) : (Y)) 28 | 29 | int ku_rect_equals(ku_rect_t r1, ku_rect_t r2) 30 | { 31 | return (r1.x == r2.x && r1.y == r2.y && r1.w == r2.w && r1.h == r2.h); 32 | } 33 | 34 | ku_rect_t ku_rect_add(ku_rect_t r1, ku_rect_t r2) 35 | { 36 | if (r1.w == 0 || r1.h == 0) return r2; 37 | if (r2.w == 0 || r2.h == 0) return r1; 38 | 39 | ku_rect_t res; 40 | 41 | res.x = VMIN(r1.x, r2.x); 42 | res.y = VMIN(r1.y, r2.y); 43 | 44 | float r1cx = r1.x + r1.w; 45 | float r1cy = r1.y + r1.h; 46 | float r2cx = r2.x + r2.w; 47 | float r2cy = r2.y + r2.h; 48 | 49 | res.w = r1cx < r2cx ? (r2cx - res.x) : (r1cx - res.x); 50 | res.h = r1cy < r2cy ? (r2cy - res.y) : (r1cy - res.y); 51 | 52 | return res; 53 | } 54 | 55 | ku_rect_t ku_rect_is(ku_rect_t l, ku_rect_t r) 56 | { 57 | ku_rect_t f = {0}; 58 | if (!(l.x + l.w < r.x || r.x + r.w < l.x || l.y + l.h < r.y || r.y + r.h < l.y)) 59 | { 60 | f.x = VMAX(l.x, r.x); 61 | f.y = VMAX(l.y, r.y); 62 | f.w = VMIN(r.x + r.w - f.x, l.x + l.w - f.x); 63 | f.h = VMIN(r.y + r.h - f.y, l.y + l.h - f.y); 64 | } 65 | 66 | return f; 67 | } 68 | 69 | void ku_rect_describe(ku_rect_t rect) 70 | { 71 | printf("%f %f %f %f\n", rect.x, rect.y, rect.w, rect.h); 72 | } 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /src/kinetic_ui/ku_renderer_egl.c: -------------------------------------------------------------------------------- 1 | #ifndef ku_renderer_egl_h 2 | #define ku_renderer_egl_h 3 | 4 | #include "ku_bitmap.c" 5 | #include "ku_rect.c" 6 | #include "mt_vector.c" 7 | 8 | void ku_renderer_egl_init(int max_device_width, int max_device_height); 9 | void ku_renderer_egl_destroy(); 10 | void ku_renderer_egl_render(mt_vector_t* views, ku_bitmap_t* bitmap, ku_rect_t dirty); 11 | void ku_renderer_egl_screenshot(ku_bitmap_t* bitmap, char* path); 12 | 13 | #endif 14 | 15 | #if __INCLUDE_LEVEL__ == 0 16 | 17 | #include "ku_gl.c" 18 | #include "ku_png.c" 19 | #include "ku_view.c" 20 | #include "mt_time.c" 21 | 22 | void ku_renderer_egl_init(int max_device_width, int max_device_height) 23 | { 24 | ku_gl_init(max_device_width, max_device_height); 25 | 26 | glClearColor(0.0, 0.0, 0.0, 1.0); 27 | } 28 | 29 | void ku_renderer_egl_destroy() 30 | { 31 | ku_gl_destroy(); 32 | } 33 | 34 | void ku_renderer_egl_render(mt_vector_t* views, ku_bitmap_t* bitmap, ku_rect_t dirty) 35 | { 36 | /* cut out dirty rect */ 37 | 38 | ku_gl_add_textures(views, 0); 39 | ku_gl_add_vertexes(views); 40 | 41 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 42 | 43 | /* we need to keep nested masks in mind */ 44 | 45 | static ku_rect_t masks[32] = {0}; 46 | static int maski = 0; 47 | 48 | masks[0] = (ku_rect_t){0, 0, bitmap->w, bitmap->h}; 49 | dirty = masks[0]; 50 | 51 | for (size_t i = 0; i < views->length; i++) 52 | { 53 | ku_view_t* view = views->data[i]; 54 | 55 | if (view->style.masked) 56 | { 57 | dirty = view->frame.global; 58 | if (view->style.shadow_blur > 0) 59 | { 60 | dirty.x -= view->style.shadow_blur; 61 | dirty.y -= view->style.shadow_blur; 62 | dirty.w += 2 * view->style.shadow_blur; 63 | dirty.h += 2 * view->style.shadow_blur; 64 | } 65 | 66 | maski++; 67 | masks[maski] = dirty; 68 | /* printf("%s masked, dirty %f %f %f %f\n", view->id, dirty.x, dirty.y, dirty.w, dirty.h); */ 69 | } 70 | 71 | if (view->texture.bitmap || view->texture.full) 72 | { 73 | bmr_t mask = (bmr_t){(int) dirty.x, (int) dirty.y, (int) (dirty.x + dirty.w), (int) (dirty.y + dirty.h)}; 74 | 75 | if (view->frame.region.w > -1 && view->frame.region.h > -1) 76 | { 77 | ku_rect_t rect = view->frame.global; 78 | 79 | bmr_t srcmsk = {(int) rect.x, (int) rect.y, (int) (rect.x + rect.w), (int) (rect.y + rect.h)}; 80 | 81 | srcmsk.x += view->frame.region.x; 82 | srcmsk.y += view->frame.region.y; 83 | srcmsk.z = srcmsk.x + view->frame.region.w; 84 | srcmsk.w = srcmsk.y + view->frame.region.h; 85 | 86 | mask = srcmsk; 87 | 88 | if (srcmsk.x != srcmsk.z) 89 | ku_gl_render_quad(bitmap, i, mask); 90 | } 91 | else 92 | { 93 | ku_gl_render_quad(bitmap, i, mask); 94 | } 95 | } 96 | 97 | if (view->style.unmask) 98 | { 99 | maski--; 100 | dirty = masks[maski]; 101 | } 102 | } 103 | 104 | /* render with dirty rects, has artifacts because of double buffering, will work on it later, won't be much more efficient though */ 105 | 106 | /* masks[0] = dirty; */ 107 | 108 | /* draw views */ 109 | 110 | /* for (size_t i = 0; i < views->length; i++) */ 111 | /* { */ 112 | /* ku_view_t* view = views->data[i]; */ 113 | 114 | /* if (view->style.masked) */ 115 | /* { */ 116 | /* dirty = ku_rect_is(masks[maski], view->frame.global); */ 117 | /* maski++; */ 118 | /* masks[maski] = dirty; */ 119 | /* /\* printf("%s masked, dirty %f %f %f %f\n", view->id, dirty.x, dirty.y, dirty.w, dirty.h); *\/ */ 120 | /* } */ 121 | 122 | /* if (view->texture.bitmap) */ 123 | /* { */ 124 | /* ku_rect_t rect = view->frame.global; */ 125 | 126 | /* bmr_t dstmsk = ku_bitmap_is( */ 127 | /* (bmr_t){(int) dirty.x, (int) dirty.y, (int) (dirty.x + dirty.w), (int) (dirty.y + dirty.h)}, */ 128 | /* (bmr_t){0, 0, bitmap->w, bitmap->h}); */ 129 | 130 | /* bmr_t srcmsk = {(int) rect.x, (int) rect.y, (int) (rect.x + rect.w), (int) (rect.y + rect.h)}; */ 131 | 132 | /* /\* if there is a region to draw, modify source mask *\/ */ 133 | 134 | /* if (view->frame.region.w > 0 && view->frame.region.h > 0) */ 135 | /* { */ 136 | /* srcmsk.x += view->frame.region.x; */ 137 | /* srcmsk.y += view->frame.region.y; */ 138 | /* srcmsk.z = srcmsk.x + view->frame.region.w; */ 139 | /* srcmsk.w = srcmsk.y + view->frame.region.h; */ 140 | /* } */ 141 | 142 | /* dstmsk = ku_bitmap_is(dstmsk, srcmsk); */ 143 | 144 | /* ku_gl_render_quad(bitmap, i, dstmsk); */ 145 | /* } */ 146 | 147 | /* if (view->style.unmask) */ 148 | /* { */ 149 | /* maski--; */ 150 | /* dirty = masks[maski]; */ 151 | /* } */ 152 | /* } */ 153 | } 154 | 155 | void ku_renderer_egl_screenshot(ku_bitmap_t* bm, char* path) 156 | { 157 | ku_bitmap_t* bitmap = ku_bitmap_new(bm->w, bm->h); 158 | ku_gl_save_framebuffer(bitmap); 159 | 160 | ku_bitmap_t* flipped = ku_bitmap_new(bm->w, bm->h); 161 | for (int y = 0; y < bitmap->h; y++) 162 | { 163 | int src_y = bitmap->h - y - 1; 164 | memcpy(flipped->data + y * bitmap->w * 4, bitmap->data + src_y * bitmap->w * 4, bitmap->w * 4); 165 | } 166 | 167 | ku_png_write(path, flipped); 168 | 169 | REL(flipped); 170 | REL(bitmap); 171 | } 172 | 173 | #endif 174 | -------------------------------------------------------------------------------- /src/kinetic_ui/ku_renderer_soft.c: -------------------------------------------------------------------------------- 1 | #ifndef ku_renderer_software_h 2 | #define ku_renderer_software_h 3 | 4 | #include "ku_bitmap.c" 5 | #include "ku_rect.c" 6 | #include "mt_vector.c" 7 | 8 | void ku_renderer_software_render(mt_vector_t* views, ku_bitmap_t* bitmap, ku_rect_t dirty); 9 | void ku_renderer_soft_screenshot(ku_bitmap_t* bitmap, char* path); 10 | 11 | #endif 12 | 13 | #if __INCLUDE_LEVEL__ == 0 14 | 15 | #include "ku_png.c" 16 | #include "ku_view.c" 17 | #include "mt_time.c" 18 | 19 | void ku_renderer_software_render(mt_vector_t* views, ku_bitmap_t* bitmap, ku_rect_t dirty) 20 | { 21 | /* cut out dirty rect */ 22 | 23 | /* ku_bitmap_cut(&mmfm.window->bitmap, (int) sum.x, (int) sum.y, (int) sum.w, (int) sum.h); */ 24 | 25 | /* draw dirty rect for debugging */ 26 | 27 | /* ku_bitmap_blend_rect(bitmap, (int) dirty.x, (int) dirty.y, (int) dirty.w, (int) dirty.h, 0x55FF0000); */ 28 | /* ku_wayland_draw_window(mmfm.window, 0, 0, mmfm.window->width, mmfm.window->height); */ 29 | 30 | /* we need to keep nested masks in mind */ 31 | 32 | static ku_rect_t masks[32] = {0}; 33 | static int maski = 0; 34 | 35 | masks[0] = dirty; 36 | 37 | /* draw views into bitmap */ 38 | 39 | for (size_t i = 0; i < views->length; i++) 40 | { 41 | ku_view_t* view = views->data[i]; 42 | 43 | if (view->style.masked) 44 | { 45 | dirty = ku_rect_is(masks[maski], view->frame.global); 46 | maski++; 47 | masks[maski] = dirty; 48 | /* printf("%s masked, dirty %f %f %f %f\n", view->id, dirty.x, dirty.y, dirty.w, dirty.h); */ 49 | } 50 | 51 | if (view->texture.bitmap) 52 | { 53 | ku_rect_t rect = view->frame.global; 54 | 55 | bmr_t dstmsk = ku_bitmap_is( 56 | (bmr_t){(int) dirty.x, (int) dirty.y, (int) (dirty.x + dirty.w), (int) (dirty.y + dirty.h)}, 57 | (bmr_t){0, 0, bitmap->w, bitmap->h}); 58 | 59 | bmr_t srcmsk = {0, 0, view->texture.bitmap->w, view->texture.bitmap->h}; 60 | 61 | /* if there is a region to draw, modify source mask */ 62 | 63 | if (view->frame.region.w > -1 && view->frame.region.h > -1) 64 | { 65 | srcmsk.x += view->frame.region.x; 66 | srcmsk.y += view->frame.region.y; 67 | srcmsk.z = srcmsk.x + view->frame.region.w; 68 | srcmsk.w = srcmsk.y + view->frame.region.h; 69 | } 70 | 71 | /* draw with shadow blur outlets in mind */ 72 | 73 | if (view->texture.transparent == 0 || i == 0) 74 | { 75 | ku_bitmap_insert( 76 | bitmap, 77 | dstmsk, 78 | view->texture.bitmap, 79 | srcmsk, 80 | rect.x - view->style.shadow_blur, 81 | rect.y - view->style.shadow_blur); 82 | } 83 | else 84 | { 85 | if (view->texture.alpha == 1.0) 86 | { 87 | ku_bitmap_blend( 88 | bitmap, 89 | dstmsk, 90 | view->texture.bitmap, 91 | srcmsk, 92 | rect.x - view->style.shadow_blur, 93 | rect.y - view->style.shadow_blur); 94 | } 95 | else 96 | { 97 | ku_bitmap_blend_with_alpha( 98 | bitmap, 99 | dstmsk, 100 | view->texture.bitmap, 101 | srcmsk, 102 | rect.x - view->style.shadow_blur, 103 | rect.y - view->style.shadow_blur, 104 | (255 - (int) (view->texture.alpha * 255.0))); 105 | } 106 | } 107 | } 108 | 109 | if (view->style.unmask) 110 | { 111 | maski--; 112 | dirty = masks[maski]; 113 | } 114 | } 115 | } 116 | 117 | void ku_renderer_soft_screenshot(ku_bitmap_t* bitmap, char* path) 118 | { 119 | ku_png_write(path, bitmap); 120 | } 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /src/kinetic_ui/texture/tg_css.c: -------------------------------------------------------------------------------- 1 | /* 2 | CSS texture generator 3 | Generates texture based on css style 4 | */ 5 | 6 | #ifndef texgen_css_h 7 | #define texgen_css_h 8 | 9 | #include "ku_bitmap.c" 10 | #include "ku_view.c" 11 | 12 | typedef struct _tg_css_t 13 | { 14 | char* id; 15 | char* path; 16 | ku_bitmap_t* bitmap; 17 | } tg_bitmap_t; 18 | 19 | void tg_css_add(ku_view_t* view); 20 | 21 | #endif 22 | 23 | #if __INCLUDE_LEVEL__ == 0 24 | 25 | #include "ku_draw.c" 26 | #include "ku_png.c" 27 | #include "mt_log.c" 28 | #include "mt_string.c" 29 | 30 | int tg_css_gen(ku_view_t* view) 31 | { 32 | if (view->frame.local.w >= 1.0 && 33 | view->frame.local.h >= 1.0) 34 | { 35 | if (strlen(view->style.background_image) > 0) 36 | { 37 | ku_bitmap_t* bm = view->texture.bitmap; 38 | 39 | if (bm == NULL || 40 | bm->w != (int) view->frame.local.w || 41 | bm->h != (int) view->frame.local.h) 42 | { 43 | bm = ku_bitmap_new((int) view->frame.local.w, (int) view->frame.local.h); // REL 0 44 | ku_view_set_texture_bmp(view, bm); 45 | REL(bm); 46 | } 47 | 48 | ku_png_load_into(view->style.background_image, bm); 49 | 50 | view->texture.transparent = 1; 51 | view->texture.changed = 0; 52 | view->texture.ready = 1; 53 | } 54 | else if (view->style.background_color) 55 | { 56 | uint32_t color = view->style.background_color; 57 | 58 | if ((color & 0xFF) < 0xFF || view->style.shadow_blur > 0 || view->style.border_radius > 0 || view->style.border_color > 0) 59 | view->texture.transparent = 1; 60 | else 61 | view->texture.transparent = 0; 62 | 63 | float w = view->frame.local.w + 2 * view->style.shadow_blur; 64 | float h = view->frame.local.h + 2 * view->style.shadow_blur; 65 | 66 | ku_bitmap_t* bm = view->texture.bitmap; 67 | 68 | if (bm == NULL || 69 | bm->w != (int) w || 70 | bm->h != (int) h) 71 | { 72 | bm = ku_bitmap_new((int) w, (int) h); // REL 0 73 | ku_view_set_texture_bmp(view, bm); 74 | REL(bm); 75 | } 76 | 77 | ku_bitmap_reset(bm); 78 | 79 | if (color > 0) 80 | ku_draw_rounded_rect(bm, 0, 0, w, h, view->style.border_radius, view->style.shadow_blur, color, view->style.shadow_color); 81 | 82 | if (view->style.border_width > 0) 83 | { 84 | ku_draw_border( 85 | bm, 86 | 0 + view->style.shadow_blur, 87 | 0 + view->style.shadow_blur, 88 | w - 2 * view->style.shadow_blur, 89 | h - 2 * view->style.shadow_blur, 90 | view->style.border_radius, 91 | view->style.border_width, 92 | view->style.border_color); 93 | } 94 | 95 | view->texture.changed = 1; 96 | view->texture.ready = 1; 97 | } 98 | } 99 | 100 | return 1; 101 | } 102 | 103 | void tg_css_add(ku_view_t* view) 104 | { 105 | if (view->tex_gen != NULL) 106 | mt_log_debug("Text generator already exist for view, cannot create a new one : %s", view->id); 107 | else 108 | { 109 | view->tex_gen = tg_css_gen; 110 | } 111 | } 112 | 113 | #endif 114 | -------------------------------------------------------------------------------- /src/kinetic_ui/texture/tg_knob.c: -------------------------------------------------------------------------------- 1 | 2 | #ifndef texgen_knob_h 3 | #define texgen_knob_h 4 | 5 | #include "ku_view.c" 6 | 7 | typedef struct _tg_knob_t 8 | { 9 | float angle; 10 | ku_bitmap_t* back; 11 | ku_bitmap_t* fore; 12 | } tg_knob_t; 13 | 14 | void tg_knob_add(ku_view_t* view); 15 | void tg_knob_set_angle(ku_view_t* view, float angle); 16 | 17 | #endif 18 | 19 | #if __INCLUDE_LEVEL__ == 0 20 | 21 | #include "ku_draw.c" 22 | 23 | int tg_knob_gen(ku_view_t* view) 24 | { 25 | tg_knob_t* tg = view->tex_gen_data; 26 | 27 | if (view->frame.local.w > 0 && view->frame.local.h > 0) 28 | { 29 | 30 | float dist0 = 5 * view->style.scale; 31 | float dist1 = 27 * view->style.scale; 32 | float dist8 = 28 * view->style.scale; 33 | float dist2 = 31 * view->style.scale; 34 | float dist3 = 35 * view->style.scale; 35 | 36 | if (view->texture.bitmap == NULL && view->frame.local.w > 0 && view->frame.local.h > 0) 37 | { 38 | ku_bitmap_t* bmp = ku_bitmap_new(view->frame.local.w, view->frame.local.h); // REL 0 39 | tg->back = ku_bitmap_new(view->frame.local.w, view->frame.local.h); // REL 1 40 | tg->fore = ku_bitmap_new(view->frame.local.w, view->frame.local.h); // REL 2 41 | 42 | uint32_t basecol = 0x454545FF; 43 | uint32_t outercol = 0x343434FF; 44 | uint32_t centercol = 0x676767FF; 45 | uint32_t shadowcol = 0xABABAB0A; 46 | 47 | /* ku_draw_arc_grad(tg->back, */ 48 | /* (view->frame.local.w - 1.0) / 2.0, */ 49 | /* (view->frame.local.h - 1.0) / 2.0, */ 50 | /* (view->frame.local.w / 2.0) - 3.0, */ 51 | /* (view->frame.local.w / 2.0), */ 52 | /* 0, */ 53 | /* 3.14 * 2, */ 54 | /* 0x00000044, */ 55 | /* 0); */ 56 | 57 | ku_draw_arc_grad(tg->back, (view->frame.local.w - 1.0) / 2.0, (view->frame.local.h - 1.0) / 2.0, 0, (view->frame.local.w / 2.0) - dist0, 0, 3.14 * 2, basecol, basecol); 58 | ku_draw_arc_grad(tg->back, (view->frame.local.w - 1.0) / 2.0, (view->frame.local.h - 1.0) / 2.0, dist1, dist3, 0, 3.14 * 2, outercol, outercol); 59 | ku_draw_arc_grad(tg->back, (view->frame.local.w - 1.0) / 2.0, (view->frame.local.h - 1.0) / 2.0, (view->frame.local.w / 2.0) - dist0, (view->frame.local.w / 2.0) - 2.0, 0, 3.14 * 2, shadowcol, 0x00000000); 60 | 61 | ku_draw_arc_grad(tg->fore, (view->frame.local.w - 1.0) / 2.0, (view->frame.local.h - 1.0) / 2.0, dist1, dist2, 0, 3.14 * 2, shadowcol, 0); 62 | ku_draw_arc_grad(tg->fore, (view->frame.local.w - 1.0) / 2.0, (view->frame.local.h - 1.0) / 2.0, 0, dist8, 0, 3.14 * 2, centercol, centercol); 63 | ku_view_set_texture_bmp(view, bmp); 64 | 65 | REL(bmp); // REL 0 66 | } 67 | 68 | if (tg->angle < 0) 69 | tg->angle += 6.28; 70 | 71 | ku_draw_insert(view->texture.bitmap, tg->back, 0, 0); 72 | 73 | if (tg->angle > 3.14 * 3 / 2) 74 | { 75 | ku_draw_arc_grad(view->texture.bitmap, (view->frame.local.w - 1.0) / 2.0, (view->frame.local.h - 1.0) / 2.0, dist1, dist3, 3.14 * 3 / 2, tg->angle, 0x999999FF, 0x999999FF); 76 | } 77 | else 78 | { 79 | ku_draw_arc_grad(view->texture.bitmap, (view->frame.local.w - 1.0) / 2.0, (view->frame.local.h - 1.0) / 2.0, dist1, dist3, 3.14 * 3 / 2, 6.28, 0x999999FF, 0x999999FF); 80 | ku_draw_arc_grad(view->texture.bitmap, (view->frame.local.w - 1.0) / 2.0, (view->frame.local.h - 1.0) / 2.0, dist1, dist3, 0, tg->angle, 0x999999FF, 0x999999FF); 81 | } 82 | 83 | ku_draw_blend_argb(view->texture.bitmap, 0, 0, tg->fore); 84 | view->texture.changed = 1; 85 | view->texture.ready = 1; 86 | } 87 | 88 | return 1; 89 | } 90 | 91 | void tg_knob_del(void* p) 92 | { 93 | tg_knob_t* tg = p; 94 | if (tg->back) REL(tg->back); 95 | if (tg->fore) REL(tg->fore); 96 | } 97 | 98 | void tg_knob_desc(void* p, int level) 99 | { 100 | printf("tg_knob"); 101 | } 102 | 103 | void tg_knob_add(ku_view_t* view) 104 | { 105 | assert(view->tex_gen == NULL); 106 | 107 | tg_knob_t* tg = CAL(sizeof(tg_knob_t), tg_knob_del, tg_knob_desc); 108 | tg->angle = 3 * 3.14 / 2; 109 | 110 | view->tex_gen_data = tg; 111 | view->tex_gen = tg_knob_gen; 112 | } 113 | 114 | void tg_knob_set_angle(ku_view_t* view, float angle) 115 | { 116 | tg_knob_t* tg = view->tex_gen_data; 117 | 118 | tg->angle = angle; 119 | view->texture.ready = 0; // force rerender 120 | } 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /src/kinetic_ui/texture/tg_scaledimg.c: -------------------------------------------------------------------------------- 1 | /* 2 | CSS texture generator 3 | Generates texture based on css style 4 | */ 5 | 6 | #ifndef texgen_scaledimg_h 7 | #define texgen_scaledimg_h 8 | 9 | #include "ku_bitmap.c" 10 | #include "ku_view.c" 11 | 12 | typedef struct _tg_scaledimg_t 13 | { 14 | int w; 15 | int h; 16 | } tg_scaledimg_t; 17 | 18 | void tg_scaledimg_add(ku_view_t* view, int w, int h); 19 | int tg_scaledimg_gen(ku_view_t* view); 20 | void tg_scaledimg_set_content_size(ku_view_t* view, int w, int h); 21 | 22 | #endif 23 | 24 | #if __INCLUDE_LEVEL__ == 0 25 | 26 | #include "ku_draw.c" 27 | #include "mt_string.c" 28 | 29 | int tg_scaledimg_gen(ku_view_t* view) 30 | { 31 | tg_scaledimg_t* gen = view->tex_gen_data; 32 | ku_bitmap_t* bm = view->texture.bitmap; 33 | 34 | /* just resize texture bitmap with the view */ 35 | 36 | if (bm == NULL || 37 | bm->w != (int) gen->w || 38 | bm->h != (int) gen->h) 39 | { 40 | bm = ku_bitmap_new_aligned((int) gen->w, (int) gen->h, 16); // REL 0 41 | 42 | ku_view_set_texture_bmp(view, bm); 43 | 44 | ku_draw_rect(bm, 0, 0, bm->w, bm->h, 0x00000000, 0); 45 | 46 | REL(bm); 47 | } 48 | 49 | view->texture.ready = 1; 50 | 51 | return 1; 52 | } 53 | 54 | void tg_scaledimg_set_content_size(ku_view_t* view, int w, int h) 55 | { 56 | tg_scaledimg_t* gen = view->tex_gen_data; 57 | 58 | gen->w = w; 59 | gen->h = h; 60 | } 61 | 62 | void tg_scaledimg_add(ku_view_t* view, int w, int h) 63 | { 64 | assert(view->tex_gen == NULL); 65 | 66 | tg_scaledimg_t* gen = CAL(sizeof(tg_scaledimg_t), NULL, NULL); 67 | gen->w = w; 68 | gen->h = h; 69 | 70 | view->tex_gen_data = gen; 71 | view->tex_gen = tg_scaledimg_gen; 72 | } 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /src/kinetic_ui/texture/tg_text.c: -------------------------------------------------------------------------------- 1 | /* 2 | Text texture generator 3 | Shows text in view 4 | */ 5 | 6 | #ifndef texgen_text_h 7 | #define texgen_text_h 8 | 9 | #include "ku_text.c" 10 | #include "ku_view.c" 11 | 12 | typedef struct _tg_text_t 13 | { 14 | char* text; 15 | float scale; 16 | textstyle_t style; 17 | } tg_text_t; 18 | 19 | void tg_text_add(ku_view_t* view); 20 | void tg_text_set(ku_view_t* view, char* text, textstyle_t style); 21 | void tg_text_set1(ku_view_t* view, char* text); 22 | char* tg_text_get(ku_view_t* view); 23 | void tg_text_set_style(ku_view_t* view, textstyle_t style); 24 | 25 | #endif 26 | 27 | #if __INCLUDE_LEVEL__ == 0 28 | 29 | #include "ku_bitmap.c" 30 | #include "ku_draw.c" 31 | #include "ku_gen_textstyle.c" 32 | #include "mt_string.c" 33 | #include "tg_css.c" 34 | 35 | int tg_text_index = 0; 36 | 37 | int tg_text_gen(ku_view_t* view) 38 | { 39 | tg_text_t* gen = view->tex_gen_data; 40 | if (view->frame.local.w > 0 && view->frame.local.h > 0) 41 | { 42 | if (gen->scale != view->style.scale) 43 | { 44 | float ratio; 45 | if (gen->scale == 0.0) 46 | ratio = view->style.scale; 47 | else 48 | ratio = view->style.scale / gen->scale; 49 | gen->style.size *= ratio; 50 | gen->scale = view->style.scale; 51 | } 52 | 53 | ku_bitmap_t* fontmap = ku_bitmap_new((int) view->frame.local.w, (int) view->frame.local.h); // REL 0 54 | textstyle_t style = gen->style; 55 | 56 | if ((style.textcolor & 0xFF) < 0xFF || (style.backcolor & 0xFF) < 0xFF) 57 | view->texture.transparent = 1; 58 | else 59 | view->texture.transparent = 0; 60 | 61 | if ((gen->text != NULL) && strlen(gen->text) > 0) 62 | { 63 | ku_text_render(gen->text, style, fontmap); 64 | } 65 | else 66 | { 67 | ku_draw_rect(fontmap, 0, 0, fontmap->w, fontmap->h, style.backcolor, 0); 68 | } 69 | 70 | ku_view_set_texture_bmp(view, fontmap); 71 | 72 | REL(fontmap); // REL 0 73 | } 74 | 75 | return 1; 76 | } 77 | 78 | void tg_text_del(void* p) 79 | { 80 | tg_text_t* gen = p; 81 | if (gen->text) REL(gen->text); 82 | } 83 | 84 | void tg_text_desc(void* p, int level) 85 | { 86 | printf("tg_text"); 87 | } 88 | 89 | void tg_text_add(ku_view_t* view) 90 | { 91 | assert(view->tex_gen == NULL); 92 | 93 | tg_text_t* gen = CAL(sizeof(tg_text_t), tg_text_del, tg_text_desc); 94 | 95 | gen->text = NULL; // REL 1 96 | gen->scale = view->style.scale; 97 | gen->style = ku_gen_textstyle_parse(view); 98 | 99 | view->tex_gen_data = gen; 100 | view->tex_gen = tg_text_gen; 101 | } 102 | 103 | void tg_text_set1(ku_view_t* view, char* text) 104 | { 105 | tg_text_t* gen = view->tex_gen_data; 106 | 107 | if (gen->text) REL(gen->text); 108 | if (text) gen->text = mt_string_new_cstring(text); 109 | 110 | view->texture.ready = 0; 111 | } 112 | 113 | void tg_text_set(ku_view_t* view, char* text, textstyle_t style) 114 | { 115 | tg_text_t* gen = view->tex_gen_data; 116 | 117 | if (gen->text) REL(gen->text); 118 | if (text) gen->text = mt_string_new_cstring(text); 119 | 120 | gen->style = style; 121 | gen->style.size *= gen->scale; 122 | 123 | view->texture.ready = 0; 124 | } 125 | 126 | void tg_text_set_style(ku_view_t* view, textstyle_t style) 127 | { 128 | tg_text_t* gen = view->tex_gen_data; 129 | 130 | gen->style = style; 131 | gen->style.size *= gen->scale; 132 | view->texture.ready = 0; 133 | } 134 | 135 | char* tg_text_get(ku_view_t* view) 136 | { 137 | tg_text_t* gen = view->tex_gen_data; 138 | return gen->text; 139 | } 140 | 141 | #endif 142 | -------------------------------------------------------------------------------- /src/mt_core/mt_channel.c: -------------------------------------------------------------------------------- 1 | /* 2 | One-way non-locking communication channel between threads 3 | If mtch_send returns 0, channel is full, send data again later 4 | If mtch_recv returns 0, channel is empty 5 | */ 6 | 7 | #ifndef mt_channel_h 8 | #define mt_channel_h 9 | 10 | #include "mt_memory.c" 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | typedef struct mt_channel_t mt_channel_t; 18 | struct mt_channel_t 19 | { 20 | char* flags; 21 | void** boxes; 22 | 23 | uint32_t size; 24 | uint32_t rpos; // read position 25 | uint32_t wpos; // write position 26 | }; 27 | 28 | mt_channel_t* mt_channel_new(uint32_t size); 29 | void mt_channel_del(void* pointer); 30 | char mt_channel_send(mt_channel_t* ch, void* data); 31 | void* mt_channel_recv(mt_channel_t* ch); 32 | 33 | #endif 34 | 35 | #if __INCLUDE_LEVEL__ == 0 36 | 37 | void mt_channel_del(void* pointer) 38 | { 39 | assert(pointer != NULL); 40 | 41 | mt_channel_t* ch = pointer; 42 | 43 | REL(ch->flags); 44 | REL(ch->boxes); 45 | } 46 | 47 | void mt_channel_describe(void* p, int level) 48 | { 49 | mt_channel_t* ch = p; 50 | printf("mt_channel, size %u read pos %u write pos %u", ch->size, ch->rpos, ch->wpos); 51 | } 52 | 53 | void mt_channel_describe_flags(void* p, int level) 54 | { 55 | printf("mt_channel flags"); 56 | } 57 | 58 | void mt_channel_describe_boxes(void* p, int level) 59 | { 60 | printf("mt_channel boxes"); 61 | } 62 | 63 | mt_channel_t* mt_channel_new(uint32_t size) 64 | { 65 | mt_channel_t* ch = CAL(sizeof(mt_channel_t), mt_channel_del, mt_channel_describe); 66 | 67 | ch->flags = CAL(sizeof(char) * size, NULL, mt_channel_describe_flags); 68 | ch->boxes = CAL(sizeof(void*) * size, NULL, mt_channel_describe_boxes); 69 | ch->size = size; 70 | ch->rpos = 0; 71 | ch->wpos = 0; 72 | 73 | return ch; 74 | } 75 | 76 | char mt_channel_send(mt_channel_t* ch, void* data) 77 | { 78 | assert(ch != NULL); 79 | assert(data != NULL); 80 | 81 | // wait for the box to get empty 82 | 83 | if (ch->flags[ch->wpos] == 0) 84 | { 85 | /* swap these rows to cause a race condition and a failing test */ 86 | ch->boxes[ch->wpos] = data; // first store data 87 | ch->flags[ch->wpos] = 1; // then set flag, it doesn't have to be atomic, only the last bit counts 88 | 89 | ch->wpos += 1; // increment write index, doesn't have to be atomic, this thread uses it only 90 | if (ch->wpos == ch->size) 91 | ch->wpos = 0; 92 | 93 | return 1; 94 | } 95 | 96 | return 0; 97 | } 98 | 99 | void* mt_channel_recv(mt_channel_t* ch) 100 | { 101 | assert(ch != NULL); 102 | 103 | if (ch->flags[ch->rpos] == 1) 104 | { 105 | void* result = ch->boxes[ch->rpos]; 106 | 107 | ch->boxes[ch->rpos] = NULL; // empty box 108 | ch->flags[ch->rpos] = 0; // set flag, it doesn't have to be atomic, only the last bit counts 109 | 110 | ch->rpos += 1; // increment read index, it doesn't have to be atomic, this thread uses it only 111 | 112 | if (ch->rpos == ch->size) 113 | ch->rpos = 0; 114 | 115 | return result; 116 | } 117 | 118 | return NULL; 119 | } 120 | #endif 121 | -------------------------------------------------------------------------------- /src/mt_core/mt_log.c: -------------------------------------------------------------------------------- 1 | #ifndef _mt_log_h 2 | #define _mt_log_h 3 | 4 | #include 5 | 6 | typedef enum 7 | { 8 | MT_LOG_DEBUG = 0, 9 | MT_LOG_INFO = 1, 10 | MT_LOG_WARN = 2, 11 | MT_LOG_ERROR = 3, 12 | } mt_log_importance; 13 | 14 | void mt_log(mt_log_importance importance, const char* file, int line, const char* fmt, ...); 15 | void mt_log_set_level(mt_log_importance importance); 16 | int mt_log_get_level(); 17 | void mt_log_inc_verbosity(void); 18 | void mt_log_use_colors(bool use_colors); 19 | void mt_log_set_file_column(int column); 20 | 21 | #define mt_log_debug(...) mt_log(MT_LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) 22 | #define mt_log_info(...) mt_log(MT_LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) 23 | #define mt_log_warn(...) mt_log(MT_LOG_WARN, __FILE__, __LINE__, __VA_ARGS__) 24 | #define mt_log_error(...) mt_log(MT_LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) 25 | 26 | #define mt_log_level_debug() mt_log_set_level(MT_LOG_DEBUG); 27 | #define mt_log_level_info() mt_log_set_level(MT_LOG_INFO); 28 | #define mt_log_level_warn() mt_log_set_level(MT_LOG_WARN); 29 | #define mt_log_level_error() mt_log_set_level(MT_LOG_ERROR); 30 | 31 | #endif 32 | 33 | #if __INCLUDE_LEVEL__ == 0 34 | 35 | #define COLOR_RESET "\x1B[0m" 36 | #define COLOR_WHITE "\x1B[1;37m" 37 | #define COLOR_BLACK "\x1B[0;30m" 38 | #define COLOR_BLUE "\x1B[0;34m" 39 | #define COLOR_LIGHT_BLUE "\x1B[1;34m" 40 | #define COLOR_GREEN "\x1B[0;32m" 41 | #define COLOR_LIGHT_GREEN "\x1B[1;32m" 42 | #define COLOR_CYAN "\x1B[0;36m" 43 | #define COLOR_LIGHT_CYAN "\x1B[1;36m" 44 | #define COLOR_RED "\x1B[0;31m" 45 | #define COLOR_LIGHT_RED "\x1B[1;31m" 46 | #define COLOR_PURPLE "\x1B[0;35m" 47 | #define COLOR_LIGHT_PURPLE "\x1B[1;35m" 48 | #define COLOR_BROWN "\x1B[0;33m" 49 | #define COLOR_YELLOW "\x1B[1;33m" 50 | #define COLOR_GRAY "\x1B[0;30m" 51 | #define COLOR_LIGHT_GRAY "\x1B[0;37m" 52 | 53 | #define __USE_POSIX199309 1 54 | /* #define _POSIX_C_SOURCE 199506L */ 55 | 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | 66 | static mt_log_importance min_importance_to_log = MT_LOG_WARN; 67 | 68 | static bool use_colors = false; 69 | static int file_col = 100; 70 | 71 | static const char* verbosity_names[] = { 72 | "DEBUG", 73 | "INFO", 74 | "WARN", 75 | "ERROR", 76 | }; 77 | 78 | static const char* verbosity_colors[] = { 79 | COLOR_LIGHT_CYAN, 80 | COLOR_GREEN, 81 | COLOR_YELLOW, 82 | COLOR_LIGHT_RED, 83 | }; 84 | 85 | void mt_log(const mt_log_importance importance, const char* file, const int line, const char* fmt, ...) 86 | { 87 | if (importance < min_importance_to_log) 88 | { 89 | return; 90 | } 91 | 92 | struct timespec ts; 93 | if (clock_gettime(CLOCK_REALTIME, &ts) != 0) 94 | { 95 | fprintf(stdout, "clock_gettime() failed: %s\n", strerror(errno)); 96 | ts.tv_sec = 0; 97 | ts.tv_nsec = 0; 98 | } 99 | 100 | struct tm* my_tm = localtime(&ts.tv_sec); 101 | 102 | if (use_colors) 103 | { 104 | fprintf( 105 | stdout, 106 | "%s%-5s%s ", 107 | verbosity_colors[importance], 108 | verbosity_names[importance], 109 | COLOR_RESET); 110 | } 111 | else 112 | { 113 | fprintf(stdout, "%-5s ", verbosity_names[importance]); 114 | } 115 | 116 | va_list args; 117 | va_start(args, fmt); 118 | vfprintf(stdout, fmt, args); 119 | va_end(args); 120 | 121 | if (use_colors) 122 | { 123 | fprintf( 124 | stdout, 125 | "\033[%iG %.2i:%.2i:%.2i:%.6li %15s : %d%s ", 126 | file_col, 127 | my_tm->tm_hour, 128 | my_tm->tm_min, 129 | my_tm->tm_sec, 130 | ts.tv_nsec / 1000, 131 | file, 132 | line, 133 | COLOR_RESET); 134 | } 135 | else 136 | { 137 | fprintf( 138 | stdout, 139 | "\033[%iG %.2i:%.2i:%.2i:%.6li ( %s:%d: )", 140 | file_col, 141 | my_tm->tm_hour, 142 | my_tm->tm_min, 143 | my_tm->tm_sec, 144 | ts.tv_nsec / 1000, 145 | file, 146 | line); 147 | } 148 | 149 | fprintf(stdout, "\n"); 150 | } 151 | 152 | void mt_log_set_level(const mt_log_importance importance) 153 | { 154 | min_importance_to_log = importance; 155 | } 156 | 157 | void mt_log_use_colors(const bool colors) 158 | { 159 | use_colors = colors; 160 | } 161 | 162 | void mt_log_set_file_column(int column) 163 | { 164 | file_col = column; 165 | } 166 | 167 | void mt_log_inc_verbosity(void) 168 | { 169 | if (min_importance_to_log != MT_LOG_DEBUG) 170 | { 171 | min_importance_to_log -= 1; 172 | mt_log_debug("Set log level to %s", verbosity_names[min_importance_to_log]); 173 | } 174 | } 175 | 176 | int mt_log_get_level() 177 | { 178 | return min_importance_to_log; 179 | } 180 | 181 | #endif 182 | -------------------------------------------------------------------------------- /src/mt_core/mt_memory.c: -------------------------------------------------------------------------------- 1 | #ifndef mt_memory_h 2 | #define mt_memory_h 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define CAL(X, Y, Z) mt_memory_calloc(X, Y, Z); 12 | #define RET(X) mt_memory_retain(X) 13 | #define REL(X) mt_memory_release(X) 14 | #define HEAP(X) mt_memory_stack_to_heap(sizeof(X), NULL, NULL, (char*) &X) 15 | 16 | void* mt_memory_alloc(size_t size, void (*destructor)(void*), void (*descriptor)(void*, int)); 17 | void* mt_memory_calloc(size_t size, void (*destructor)(void*), void (*descriptor)(void*, int)); 18 | void* mt_memory_realloc(void* pointer, size_t size); 19 | void* mt_memory_retain(void* pointer); 20 | char mt_memory_release(void* pointer); 21 | size_t mt_memory_retaincount(void* pointer); 22 | void* mt_memory_stack_to_heap(size_t size, void (*destructor)(void*), void (*descriptor)(void*, int), char* data); 23 | void mt_memory_describe(void* pointer, int level); 24 | 25 | #endif 26 | 27 | #if __INCLUDE_LEVEL__ == 0 28 | 29 | struct mt_memory_head 30 | { 31 | char id[2]; 32 | void (*destructor)(void*); 33 | void (*descriptor)(void*, int); 34 | size_t retaincount; 35 | }; 36 | 37 | void* mt_memory_alloc( 38 | size_t size, /* size of data to store */ 39 | void (*destructor)(void*), /* optional destructor */ 40 | void (*descriptor)(void*, int)) /* optional descriptor for describing memory area */ 41 | { 42 | char* bytes = malloc(sizeof(struct mt_memory_head) + size); 43 | if (bytes != NULL) 44 | { 45 | struct mt_memory_head* head = (struct mt_memory_head*) bytes; 46 | 47 | head->id[0] = 'm'; 48 | head->id[1] = 't'; 49 | head->destructor = destructor; 50 | head->descriptor = descriptor; 51 | head->retaincount = 1; 52 | 53 | return bytes + sizeof(struct mt_memory_head); 54 | } 55 | else 56 | return NULL; 57 | } 58 | 59 | void* mt_memory_calloc( 60 | size_t size, /* size of data to store */ 61 | void (*destructor)(void*), /* optional destructor */ 62 | void (*descriptor)(void*, int)) /* optional descriptor for describing memory area */ 63 | { 64 | char* bytes = calloc(1, sizeof(struct mt_memory_head) + size); 65 | 66 | if (bytes != NULL) 67 | { 68 | struct mt_memory_head* head = (struct mt_memory_head*) bytes; 69 | 70 | head->id[0] = 'm'; 71 | head->id[1] = 't'; 72 | head->destructor = destructor; 73 | head->descriptor = descriptor; 74 | head->retaincount = 1; 75 | 76 | return bytes + sizeof(struct mt_memory_head); 77 | } 78 | else 79 | return NULL; 80 | } 81 | 82 | void* mt_memory_stack_to_heap( 83 | size_t size, 84 | void (*destructor)(void*), 85 | void (*descriptor)(void*, int), 86 | char* data) 87 | { 88 | char* bytes = mt_memory_alloc(size, destructor, descriptor); 89 | 90 | if (bytes != NULL) 91 | { 92 | memcpy(bytes, data, size); 93 | return bytes; 94 | } 95 | else 96 | return NULL; 97 | } 98 | 99 | void* mt_memory_realloc(void* pointer, size_t size) 100 | { 101 | assert(pointer != NULL); 102 | 103 | char* bytes = (char*) pointer; 104 | bytes -= sizeof(struct mt_memory_head); 105 | bytes = realloc(bytes, sizeof(struct mt_memory_head) + size); 106 | if (bytes != NULL) 107 | { 108 | return bytes + sizeof(struct mt_memory_head); 109 | } 110 | else 111 | return NULL; 112 | } 113 | 114 | void* mt_memory_retain(void* pointer) 115 | { 116 | assert(pointer != NULL); 117 | 118 | char* bytes = (char*) pointer; 119 | bytes -= sizeof(struct mt_memory_head); 120 | struct mt_memory_head* head = (struct mt_memory_head*) bytes; 121 | 122 | assert(head->id[0] == 'm'); 123 | assert(head->id[1] == 't'); 124 | 125 | if (head->retaincount < SIZE_MAX) 126 | { 127 | head->retaincount += 1; 128 | return pointer; 129 | } 130 | else 131 | return NULL; 132 | } 133 | 134 | char mt_memory_release(void* pointer) 135 | { 136 | assert(pointer != NULL); 137 | 138 | char* bytes = (char*) pointer; 139 | bytes -= sizeof(struct mt_memory_head); 140 | struct mt_memory_head* head = (struct mt_memory_head*) bytes; 141 | 142 | assert(head->id[0] == 'm'); 143 | assert(head->id[1] == 't'); 144 | assert(head->retaincount > 0); 145 | 146 | head->retaincount -= 1; 147 | 148 | if (head->retaincount == 0) 149 | { 150 | if (head->destructor != NULL) 151 | head->destructor(pointer); 152 | 153 | head->id[0] = '\0'; 154 | head->id[1] = '\0'; 155 | 156 | free(bytes); 157 | 158 | return 1; 159 | } 160 | 161 | return 0; 162 | } 163 | 164 | size_t mt_memory_retaincount(void* pointer) 165 | { 166 | assert(pointer != NULL); 167 | 168 | char* bytes = (char*) pointer; 169 | bytes -= sizeof(struct mt_memory_head); 170 | struct mt_memory_head* head = (struct mt_memory_head*) bytes; 171 | 172 | assert(head->id[0] == 'm'); 173 | assert(head->id[1] == 't'); 174 | 175 | return head->retaincount; 176 | } 177 | 178 | void mt_memory_describe(void* pointer, int level) 179 | { 180 | assert(pointer != NULL); 181 | 182 | char* bytes = (char*) pointer; 183 | bytes -= sizeof(struct mt_memory_head); 184 | struct mt_memory_head* head = (struct mt_memory_head*) bytes; 185 | 186 | assert(head->id[0] == 'm'); 187 | assert(head->id[1] == 't'); 188 | 189 | if (head->descriptor != NULL) 190 | { 191 | head->descriptor(pointer, ++level); 192 | } 193 | else 194 | { 195 | printf("no descriptor"); 196 | } 197 | } 198 | 199 | #endif 200 | -------------------------------------------------------------------------------- /src/mt_core/mt_number.c: -------------------------------------------------------------------------------- 1 | #ifndef mt_number_h 2 | #define mt_number_h 3 | 4 | #include 5 | 6 | typedef union 7 | { 8 | float floatv; 9 | int intv; 10 | uint32_t uint32v; 11 | } mt_number_t; 12 | 13 | mt_number_t* mt_number_new_float(float val); 14 | mt_number_t* mt_number_new_int(int val); 15 | mt_number_t* mt_number_new_uint32(uint32_t val); 16 | 17 | #endif 18 | 19 | #if __INCLUDE_LEVEL__ == 0 20 | 21 | #include "mt_memory.c" 22 | 23 | void mt_number_describe(void* p, int level) 24 | { 25 | mt_number_t* num = p; 26 | printf("num %f %i %u", num->floatv, num->intv, num->uint32v); 27 | } 28 | 29 | mt_number_t* mt_number_new_float(float val) 30 | { 31 | mt_number_t* res = CAL(sizeof(mt_number_t), NULL, mt_number_describe); 32 | res->floatv = val; 33 | return res; 34 | } 35 | 36 | mt_number_t* mt_number_new_int(int val) 37 | { 38 | mt_number_t* res = CAL(sizeof(mt_number_t), NULL, mt_number_describe); 39 | res->intv = val; 40 | return res; 41 | } 42 | 43 | mt_number_t* mt_number_new_uint32(uint32_t val) 44 | { 45 | mt_number_t* res = CAL(sizeof(mt_number_t), NULL, mt_number_describe); 46 | res->uint32v = val; 47 | return res; 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/mt_core/mt_path.c: -------------------------------------------------------------------------------- 1 | #ifndef mt_path_h 2 | #define mt_path_h 3 | 4 | #include "mt_string.c" 5 | 6 | char* mt_path_new_append(char* root, char* component); 7 | char* mt_path_new_remove_last_component(char* path); 8 | char* mt_path_new_extension(char* path); 9 | char* mt_path_new_filename(char* path); 10 | char* mt_path_new_normalize(char* path); 11 | 12 | #endif 13 | 14 | #if __INCLUDE_LEVEL__ == 0 15 | 16 | #include 17 | #include 18 | #include 19 | #ifdef __linux__ 20 | #include 21 | #endif 22 | 23 | #include "mt_log.c" 24 | #include "mt_memory.c" 25 | 26 | char* mt_path_new_append(char* root, char* component) 27 | { 28 | if (root[strlen(root) - 1] == '/') 29 | return mt_string_new_format(PATH_MAX + NAME_MAX, "%s%s", root, component); 30 | else 31 | return mt_string_new_format(PATH_MAX + NAME_MAX, "%s/%s", root, component); 32 | } 33 | 34 | char* mt_path_new_remove_last_component(char* path) 35 | { 36 | /* TODO use POSIX dirname */ 37 | int index; 38 | for (index = strlen(path) - 2; index > 0; index--) 39 | { 40 | if (path[index] == '/') 41 | { 42 | index++; 43 | break; 44 | } 45 | } 46 | 47 | if (index > -1) 48 | { 49 | char* str = CAL(index + 1, NULL, mt_string_describe); 50 | memcpy(str, path, index); 51 | return str; 52 | } 53 | else 54 | return mt_string_new_cstring("/"); 55 | } 56 | 57 | char* mt_path_new_extension(char* path) 58 | { 59 | char* ext = strrchr(path, '.'); 60 | char* res = NULL; 61 | if (ext) 62 | res = mt_string_new_cstring(ext + 1); 63 | 64 | /* int index; */ 65 | /* for (index = strlen(path) - 1; index > -1; --index) */ 66 | /* { */ 67 | /* if (path[index] == '.') */ 68 | /* { */ 69 | /* index++; */ 70 | /* break; */ 71 | /* } */ 72 | /* } */ 73 | 74 | /* int len = strlen(path) - index; */ 75 | /* char* ext = CAL(len + 1, NULL, mt_string_describe); */ 76 | /* memcpy(ext, path + index, len); */ 77 | return res; 78 | } 79 | 80 | char* mt_path_new_filename(char* path) 81 | { 82 | /* TODO use POSIX basename */ 83 | 84 | int dotindex; 85 | for (dotindex = strlen(path) - 1; dotindex > -1; --dotindex) 86 | { 87 | if (path[dotindex] == '.') 88 | break; 89 | } 90 | 91 | if (dotindex == -1) 92 | dotindex = strlen(path) - 1; 93 | 94 | int slashindex; 95 | for (slashindex = strlen(path) - 1; slashindex > -1; --slashindex) 96 | { 97 | if (path[slashindex] == '/') 98 | { 99 | slashindex++; 100 | break; 101 | } 102 | } 103 | if (slashindex == -1) 104 | slashindex = 0; 105 | int len = dotindex - slashindex; 106 | char* title = CAL(len + 1, NULL, mt_string_describe); 107 | memcpy(title, path + slashindex, len); 108 | return title; 109 | } 110 | 111 | char* mt_path_new_normalize(char* path) 112 | { 113 | char* extpath = mt_string_new_cstring(""); 114 | char* newpath = CAL(PATH_MAX, NULL, NULL); 115 | 116 | if (path[0] == '~') 117 | { 118 | /* replace tilde with home dir */ 119 | extpath = mt_string_append(extpath, getenv("HOME")); 120 | extpath = mt_string_append_sub(extpath, path, 1, strlen(path) - 1); 121 | } 122 | else 123 | extpath = mt_string_append(extpath, path); 124 | 125 | realpath(extpath, newpath); 126 | 127 | REL(extpath); 128 | 129 | /* char cwd[PATH_MAX] = {"~"}; */ 130 | /* getcwd(cwd, sizeof(cwd)); */ 131 | 132 | /* char* newpath = NULL; */ 133 | 134 | /* if (path[0] == '~') */ 135 | /* { */ 136 | /* /\* replace tilde with home dir *\/ */ 137 | /* newpath = mt_string_new_cstring(getenv("HOME")); */ 138 | /* newpath = mt_string_append_sub(newpath, path, 1, strlen(path) - 1); */ 139 | /* } */ 140 | /* else if (path[0] == '\0') */ 141 | /* { */ 142 | /* /\* empty path to root path *\/ */ 143 | /* newpath = mt_string_new_cstring("/"); */ 144 | /* } */ 145 | /* else if (path[0] != '/') */ 146 | /* { */ 147 | /* /\* insert working directory in case of relative path *\/ */ 148 | /* newpath = mt_string_new_format(PATH_MAX, "%s/%s", cwd, path); */ 149 | /* } */ 150 | /* else */ 151 | /* { */ 152 | /* newpath = mt_string_new_cstring(path); */ 153 | /* } */ 154 | 155 | /* /\* remove last component in case of double dot *\/ */ 156 | 157 | /* size_t len = strlen(newpath); */ 158 | /* if (len > 3 && newpath[len - 1] == '.' && newpath[len - 2] == '.') */ 159 | /* { */ 160 | /* for (size_t index = len - 3; index-- > 0;) */ 161 | /* { */ 162 | /* if (newpath[index] == '/') */ 163 | /* { */ 164 | /* newpath[index] = '\0'; */ 165 | /* break; */ 166 | /* } */ 167 | /* } */ 168 | /* } */ 169 | 170 | return newpath; 171 | } 172 | 173 | #endif 174 | -------------------------------------------------------------------------------- /src/mt_core/mt_string.c: -------------------------------------------------------------------------------- 1 | #ifndef mt_string_h 2 | #define mt_string_h 3 | 4 | #include "mt_vector.c" 5 | #include 6 | #include 7 | #include 8 | 9 | #define STRNC(x) mt_string_new_cstring(x) 10 | #define STRNF(x, ...) mt_string_new_format(x, __VA_ARGS__) 11 | 12 | char* mt_string_new_format(int size, char* format, ...); 13 | char* mt_string_new_cstring(char* string); 14 | char* mt_string_new_substring(char* string, size_t from, size_t len); 15 | char* mt_string_reset(char* str); 16 | 17 | char* mt_string_append(char* str, char* add); 18 | char* mt_string_append_cp(char* str, uint32_t cp); 19 | char* mt_string_append_sub(char* str, char* add, size_t from, size_t len); 20 | 21 | char* mt_string_delete_utf_codepoints(char* str, size_t from, size_t len); 22 | mt_vector_t* mt_string_tokenize(char* str, char* del); 23 | void mt_string_describe(void* p, int level); 24 | void mt_string_describe_utf(char* str); 25 | 26 | #endif 27 | 28 | #if __INCLUDE_LEVEL__ == 0 29 | 30 | #include "mt_memory.c" 31 | #include "utf8.h" 32 | #include 33 | #include 34 | 35 | void mt_string_del(void* p) 36 | { 37 | /* printf("DEL %s\n", (char*) p); */ 38 | } 39 | 40 | char* mt_string_new_format(int size, char* format, ...) 41 | { 42 | char* result = CAL(sizeof(char) * size, mt_string_del, mt_string_describe); 43 | va_list args; 44 | 45 | va_start(args, format); 46 | vsnprintf(result, size, format, args); 47 | va_end(args); 48 | 49 | return result; 50 | } 51 | 52 | char* mt_string_new_cstring(char* string) 53 | { 54 | char* result = NULL; 55 | if (string != NULL) 56 | { 57 | result = CAL((strlen(string) + 1) * sizeof(char), mt_string_del, mt_string_describe); 58 | memcpy(result, string, strlen(string)); 59 | } 60 | return result; 61 | } 62 | 63 | /* TODO calculate UTF8 length */ 64 | 65 | char* mt_string_new_substring(char* string, size_t from, size_t len) 66 | { 67 | char* result = NULL; 68 | if (string != NULL && len > from) 69 | { 70 | result = CAL((strlen(string) + 1) * sizeof(char), mt_string_del, mt_string_describe); 71 | memcpy(result, string + from, len); 72 | result[len] = '\0'; 73 | } 74 | return result; 75 | } 76 | 77 | char* mt_string_reset(char* str) 78 | { 79 | str[0] = '\0'; 80 | return str; 81 | } 82 | 83 | char* mt_string_append(char* str, char* add) 84 | { 85 | size_t needed = strlen(str) + strlen(add) + 1; 86 | 87 | if (strlen(str) < needed) 88 | str = mt_memory_realloc(str, needed); 89 | 90 | str = utf8cat(str, add); 91 | 92 | return str; 93 | } 94 | 95 | char* mt_string_append_cp(char* str, uint32_t cp) 96 | { 97 | size_t size = utf8size(str); 98 | size_t cpsize = utf8codepointsize(cp); 99 | size_t needed = strlen(str) + size + 1; 100 | 101 | if (strlen(str) < needed) 102 | str = mt_memory_realloc(str, needed); 103 | 104 | char* end = str + size - 1; 105 | 106 | end = utf8catcodepoint(end, cp, cpsize); 107 | end[0] = '\0'; 108 | 109 | return str; 110 | } 111 | 112 | char* mt_string_append_sub(char* str, char* add, size_t from, size_t len) 113 | { 114 | size_t needed = strlen(str) + len + 1; 115 | int oldsize = strlen(str); 116 | 117 | if (strlen(str) < needed) 118 | str = mt_memory_realloc(str, needed); 119 | memcpy(str + oldsize, add + from, len); 120 | str[needed - 1] = '\0'; 121 | 122 | return str; 123 | } 124 | 125 | char* mt_string_delete_utf_codepoints(char* str, size_t from, size_t len) 126 | { 127 | char* res = STRNC(""); 128 | 129 | char* curr = str; 130 | utf8_int32_t cp; 131 | 132 | for (size_t index = 0; index < utf8len(str); index++) 133 | { 134 | curr = utf8codepoint(curr, &cp); 135 | 136 | if (index < from || index > from + len) 137 | res = mt_string_append_cp(res, cp); 138 | } 139 | 140 | strcpy(str, res); 141 | REL(res); 142 | 143 | return str; 144 | } 145 | 146 | mt_vector_t* mt_string_tokenize(char* str, char* del) 147 | { 148 | char* token; 149 | char* copy = mt_string_new_cstring(str); 150 | mt_vector_t* result = VNEW(); 151 | 152 | token = strtok(copy, del); 153 | 154 | while (token != NULL) 155 | { 156 | char* txt = CAL(strlen(token) + 1, NULL, mt_string_describe); 157 | memcpy(txt, token, strlen(token)); 158 | 159 | VADDR(result, txt); 160 | 161 | token = strtok(NULL, del); 162 | } 163 | 164 | REL(copy); 165 | 166 | return result; 167 | } 168 | 169 | void mt_string_describe(void* p, int level) 170 | { 171 | printf("STR: %s", (char*) p); 172 | } 173 | 174 | void mt_string_describe_utf(char* str) 175 | { 176 | char* part = str; 177 | utf8_int32_t cp; 178 | for (size_t i = 0; i < utf8len(str); i++) 179 | { 180 | part = utf8codepoint(part, &cp); 181 | printf("%.4i \t| ", cp); 182 | } 183 | printf("\n"); 184 | part = str; 185 | for (size_t i = 0; i < utf8len(str); i++) 186 | { 187 | part = utf8codepoint(part, &cp); 188 | printf("%c \t| ", cp); 189 | } 190 | part = str; 191 | printf("\n"); 192 | for (size_t i = 0; i < utf8len(str); i++) 193 | { 194 | part = utf8codepoint(part, &cp); 195 | printf("%zu \t| ", utf8codepointsize(cp)); 196 | } 197 | printf("\n"); 198 | } 199 | 200 | #endif 201 | -------------------------------------------------------------------------------- /src/mt_core/mt_time.c: -------------------------------------------------------------------------------- 1 | #ifndef _mt_time_h 2 | #define _mt_time_h 3 | 4 | void mt_time(char* id); 5 | 6 | #endif 7 | 8 | #if __INCLUDE_LEVEL__ == 0 9 | 10 | #include "mt_log.c" 11 | #include 12 | #include 13 | 14 | struct timeval mt_time_stamp; 15 | 16 | void mt_time(char* id) 17 | { 18 | if (id) 19 | { 20 | struct timeval ts; 21 | gettimeofday(&ts, NULL); 22 | mt_log_debug("%s time is %lu us", id, (ts.tv_sec - mt_time_stamp.tv_sec) * 1000000 + ts.tv_usec - mt_time_stamp.tv_usec); 23 | mt_time_stamp = ts; 24 | } 25 | else 26 | { 27 | gettimeofday(&mt_time_stamp, NULL); 28 | } 29 | } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/mt_core/mt_wrapper.c: -------------------------------------------------------------------------------- 1 | /* wraps a non-mtmemory managed pointer */ 2 | 3 | #ifndef mt_wrapper_h 4 | #define mt_wrapper_h 5 | 6 | #include 7 | 8 | typedef struct 9 | { 10 | void* data; 11 | } mt_wrapper_t; 12 | 13 | mt_wrapper_t* mt_wrapper_new(void* pointer); 14 | 15 | #endif 16 | 17 | #if __INCLUDE_LEVEL__ == 0 18 | 19 | #include "mt_memory.c" 20 | 21 | mt_wrapper_t* mt_wrapper_new(void* pointer) 22 | { 23 | mt_wrapper_t* res = CAL(sizeof(mt_wrapper_t), NULL, NULL); 24 | res->data = pointer; 25 | return res; 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/mt_core_ext/ku_bitmap_ext.c: -------------------------------------------------------------------------------- 1 | #ifndef bm_util_h 2 | #define bm_util_h 3 | 4 | #include "ku_bitmap.c" 5 | #include 6 | 7 | ku_bitmap_t* bm_new_flip_y(ku_bitmap_t* bm); 8 | void bm_write(ku_bitmap_t* bm, char* path); 9 | 10 | #endif 11 | 12 | #if __INCLUDE_LEVEL__ == 0 13 | 14 | ku_bitmap_t* bm_new_flip_y(ku_bitmap_t* bm) 15 | { 16 | ku_bitmap_t* tmp = ku_bitmap_new(bm->w, bm->h); 17 | for (int y = 0; y < bm->h; y++) 18 | { 19 | int src_y = bm->h - y - 1; 20 | memcpy(tmp->data + y * bm->w * 4, bm->data + src_y * bm->w * 4, bm->w * 4); 21 | } 22 | return tmp; 23 | } 24 | 25 | void bm_write(ku_bitmap_t* bm, char* path) 26 | { 27 | int w = bm->w; 28 | int h = bm->h; 29 | 30 | FILE* f; 31 | unsigned char* img = NULL; 32 | int filesize = 54 + 3 * w * h; // w is your image width, h is image height, both int 33 | 34 | img = (unsigned char*) malloc(3 * w * h); 35 | memset(img, 0, 3 * w * h); 36 | 37 | for (int i = 0; i < w; i++) 38 | { 39 | for (int j = 0; j < h; j++) 40 | { 41 | int index = j * w * 4 + i * 4; 42 | 43 | int x = i; 44 | int y = j; 45 | 46 | int r = bm->data[index]; 47 | int g = bm->data[index + 1]; 48 | int b = bm->data[index + 2]; 49 | 50 | if (r > 255) r = 255; 51 | if (g > 255) g = 255; 52 | if (b > 255) b = 255; 53 | 54 | img[(x + y * w) * 3 + 2] = (unsigned char) (r); 55 | img[(x + y * w) * 3 + 1] = (unsigned char) (g); 56 | img[(x + y * w) * 3 + 0] = (unsigned char) (b); 57 | } 58 | } 59 | 60 | unsigned char bmpfileheader[14] = {'B', 'M', 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0}; 61 | unsigned char bmpinfoheader[40] = {40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 24, 0}; 62 | unsigned char bmppad[3] = {0, 0, 0}; 63 | 64 | bmpfileheader[2] = (unsigned char) (filesize); 65 | bmpfileheader[3] = (unsigned char) (filesize >> 8); 66 | bmpfileheader[4] = (unsigned char) (filesize >> 16); 67 | bmpfileheader[5] = (unsigned char) (filesize >> 24); 68 | 69 | bmpinfoheader[4] = (unsigned char) (w); 70 | bmpinfoheader[5] = (unsigned char) (w >> 8); 71 | bmpinfoheader[6] = (unsigned char) (w >> 16); 72 | bmpinfoheader[7] = (unsigned char) (w >> 24); 73 | bmpinfoheader[8] = (unsigned char) (h); 74 | bmpinfoheader[9] = (unsigned char) (h >> 8); 75 | bmpinfoheader[10] = (unsigned char) (h >> 16); 76 | bmpinfoheader[11] = (unsigned char) (h >> 24); 77 | 78 | f = fopen(path, "wb"); 79 | fwrite(bmpfileheader, 1, 14, f); 80 | fwrite(bmpinfoheader, 1, 40, f); 81 | for (int i = 0; i < h; i++) 82 | { 83 | fwrite(img + (w * (h - i - 1) * 3), 3, w, f); 84 | fwrite(bmppad, 1, (4 - (w * 3) % 4) % 4, f); 85 | } 86 | 87 | free(img); 88 | fclose(f); 89 | } 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /src/mt_core_ext/mt_map_ext.c: -------------------------------------------------------------------------------- 1 | #ifndef mt_maputil_h 2 | #define mt_maputil_h 3 | 4 | #include "mt_map.c" 5 | #include "mt_string.c" 6 | 7 | typedef struct _mpair_t 8 | { 9 | char* key; 10 | char* value; 11 | } mpair_t; 12 | 13 | mt_map_t* mapu_pair(mpair_t pair); 14 | 15 | #endif 16 | 17 | #if __INCLUDE_LEVEL__ == 0 18 | 19 | mt_map_t* mapu_pair(mpair_t pair) 20 | { 21 | mt_map_t* result = MNEW(); 22 | char* str = mt_string_new_cstring(pair.value); // REL 0 23 | MPUT(result, pair.key, str); 24 | REL(str); // REL 0 25 | REL(pair.value); 26 | return result; 27 | } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/mt_core_ext/mt_string_ext.c: -------------------------------------------------------------------------------- 1 | #ifndef cstr_util_h 2 | #define cstr_util_h 3 | 4 | #include "mt_string.c" 5 | #include "mt_vector.c" 6 | #include 7 | #include 8 | 9 | char* mt_string_new_file(char* path); 10 | uint32_t mt_string_color_from_cstring(char* string); 11 | char* mt_string_new_readablec(uint32_t length); 12 | char* mt_string_new_alphanumeric(uint32_t length); 13 | void mt_string_tolower(char* str); 14 | mt_vector_t* mt_string_split(char* str, char* del); 15 | char* mt_string_unescape(char* str); 16 | 17 | #endif 18 | 19 | #if __INCLUDE_LEVEL__ == 0 20 | 21 | #include "mt_memory.c" 22 | 23 | static char hexa[] = 24 | { 25 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0..9 26 | 0, 27 | 0, 28 | 0, 29 | 0, 30 | 0, 31 | 0, 32 | 0, 33 | 0, 34 | 0, 35 | 0, // 10..19 36 | 0, 37 | 0, 38 | 0, 39 | 0, 40 | 0, 41 | 0, 42 | 0, 43 | 0, 44 | 0, 45 | 0, // 20..29 46 | 0, 47 | 0, 48 | 0, 49 | 0, 50 | 0, 51 | 0, 52 | 0, 53 | 0, 54 | 0, 55 | 0, // 30..39 56 | 0, 57 | 0, 58 | 0, 59 | 0, 60 | 0, 61 | 0, 62 | 0, 63 | 0, 64 | 0, 65 | 1, // 40..49 66 | 2, 67 | 3, 68 | 4, 69 | 5, 70 | 6, 71 | 7, 72 | 8, 73 | 9, 74 | 0, 75 | 0, // 50..59 76 | 0, 77 | 0, 78 | 0, 79 | 0, 80 | 0, 81 | 10, 82 | 11, 83 | 12, 84 | 13, 85 | 14, // 60..69 86 | 15, 87 | 0, 88 | 0, 89 | 0, 90 | 0, 91 | 0, 92 | 0, 93 | 0, 94 | 0, 95 | 0, // 70..79 96 | 0, 97 | 0, 98 | 0, 99 | 0, 100 | 0, 101 | 0, 102 | 0, 103 | 0, 104 | 0, 105 | 0, // 80..89 106 | 0, 107 | 0, 108 | 0, 109 | 0, 110 | 0, 111 | 0, 112 | 0, 113 | 10, 114 | 11, 115 | 12, // 90..99 116 | 13, 117 | 14, 118 | 15, 119 | 0, 120 | 0, 121 | 0, 122 | 0, 123 | 0, 124 | 0, 125 | 0 // 100..109 126 | }; 127 | 128 | /* returns uint value based on digits */ 129 | 130 | uint32_t mt_string_color_from_cstring(char* string) 131 | { 132 | uint32_t result = 0; 133 | while (*string != 0) 134 | result = result << 4 | hexa[(int) *string++]; 135 | return result; 136 | } 137 | 138 | /* reads up text file */ 139 | 140 | char* mt_string_new_file(char* path) 141 | { 142 | char* buffer = NULL; 143 | int string_size, read_size; 144 | FILE* handler = fopen(path, "r"); 145 | 146 | if (handler) 147 | { 148 | // Seek the last byte of the file 149 | fseek(handler, 0, SEEK_END); 150 | // Offset from the first to the last byte, or in other words, filesize 151 | string_size = ftell(handler); 152 | // go back to the start of the file 153 | rewind(handler); 154 | 155 | // Allocate a string that can hold it all 156 | buffer = (char*) CAL(sizeof(char) * (string_size + 1), NULL, mt_string_describe); 157 | 158 | // Read it all in one operation 159 | read_size = fread(buffer, sizeof(char), string_size, handler); 160 | 161 | // fread doesn't set it so put a \0 in the last position 162 | // and buffer is now officially a string 163 | buffer[string_size] = '\0'; 164 | 165 | if (string_size != read_size) 166 | { 167 | // Something went wrong, throw away the memory and set 168 | // the buffer to NULL 169 | free(buffer); 170 | buffer = NULL; 171 | } 172 | 173 | // Always remember to close the file. 174 | fclose(handler); 175 | } 176 | 177 | return buffer; 178 | } 179 | 180 | /* generates readable string */ 181 | 182 | char* vowels = "aeiou"; 183 | char* consonants = "bcdefghijklmnpqrstvwxyz"; 184 | 185 | char* mt_string_new_readablec(uint32_t length) 186 | { 187 | char* result = CAL(sizeof(char) * (length + 1), NULL, mt_string_describe); 188 | for (size_t index = 0; index < length; index += 2) 189 | { 190 | result[index] = consonants[rand() % strlen(consonants)]; 191 | if (index + 1 < length) 192 | result[index + 1] = vowels[rand() % strlen(vowels)]; 193 | } 194 | return result; 195 | } 196 | 197 | void mt_string_tolower(char* str) 198 | { 199 | for (size_t index = 0; index < strlen(str); index++) 200 | { 201 | str[index] = tolower(str[index]); 202 | } 203 | } 204 | 205 | /* generates alphanumeric string */ 206 | 207 | char* mt_string_alphanumeric = 208 | "0123456789" 209 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 210 | "abcdefghijklmnopqrstuvwxyz"; 211 | 212 | char* mt_string_new_alphanumeric(uint32_t length) 213 | { 214 | char* result = CAL(sizeof(char) * (length + 1), NULL, mt_string_describe); 215 | for (size_t index = 0; index < length; index++) 216 | { 217 | result[index] = mt_string_alphanumeric[rand() % strlen(mt_string_alphanumeric)]; 218 | } 219 | return result; 220 | } 221 | 222 | mt_vector_t* mt_string_split(char* str, char* del) 223 | { 224 | char* token; 225 | mt_vector_t* result = VNEW(); 226 | 227 | char* copy = mt_string_new_cstring(str); 228 | token = strtok(copy, del); 229 | 230 | while (token != NULL) 231 | { 232 | char* txt = CAL(strlen(token) + 1, NULL, mt_string_describe); 233 | memcpy(txt, token, strlen(token)); 234 | 235 | VADDR(result, txt); 236 | 237 | token = strtok(NULL, del); 238 | } 239 | 240 | REL(copy); 241 | 242 | return result; 243 | } 244 | 245 | char* mt_string_unescape(char* str) 246 | { 247 | size_t length = strlen(str); 248 | char* result = CAL((length + 1) * sizeof(char), NULL, mt_string_describe); 249 | int ni = 0; 250 | for (size_t index = 0; index < length; index++) 251 | { 252 | if (str[index] == '\\') 253 | { 254 | if (index < length - 1) 255 | { 256 | char n = str[index + 1]; 257 | if (n == '\\' || n == '"' || n == '\'' || n == '/' || n == '?') 258 | { 259 | result[ni++] = n; 260 | } 261 | index += 1; 262 | } 263 | } 264 | else 265 | { 266 | result[ni++] = str[index]; 267 | } 268 | } 269 | return result; 270 | } 271 | 272 | #endif 273 | -------------------------------------------------------------------------------- /src/mt_core_test/mt_channel_test.c: -------------------------------------------------------------------------------- 1 | #ifndef mt_channel_test_h 2 | #define mt_channel_test_h 3 | 4 | void mt_channel_test_main(); 5 | 6 | #endif 7 | 8 | #if __INCLUDE_LEVEL__ == 0 9 | 10 | #include "mt_channel.c" 11 | #include "mt_log.c" 12 | #include "mt_map.c" 13 | 14 | #define kChTestThreads 20 15 | #define kChTestMax 60000 16 | 17 | static int success = 1; 18 | 19 | void* send_test(void* chp) 20 | { 21 | mt_channel_t* ch = chp; 22 | uint32_t counter = 0; 23 | while (1) 24 | { 25 | if (success == 0) 26 | break; 27 | 28 | uint32_t* number = CAL(sizeof(uint32_t), NULL, NULL); 29 | *number = counter; 30 | char sent = mt_channel_send(ch, number); 31 | 32 | if (sent == 0) 33 | { 34 | REL(number); 35 | } 36 | else 37 | { 38 | counter += 1; 39 | if (counter == kChTestMax) 40 | break; 41 | } 42 | 43 | // struct timespec time; 44 | // time.tv_sec = 0; 45 | // time.tv_nsec = rand() % 100000; 46 | // nanosleep(&time , (struct timespec *)NULL); 47 | } 48 | 49 | return NULL; 50 | } 51 | 52 | void* recv_test(void* chp) 53 | { 54 | mt_channel_t* ch = chp; 55 | uint32_t last = 0; 56 | while (1) 57 | { 58 | if (success == 0) 59 | break; 60 | 61 | uint32_t* number = mt_channel_recv(ch); 62 | if (number != NULL) 63 | { 64 | if (*number != last) 65 | { 66 | success = 0; 67 | /* printf("index error!!! %u %u %i\n", *number, last, success); */ 68 | break; 69 | } 70 | 71 | REL(number); 72 | last += 1; 73 | 74 | if (last == kChTestMax) 75 | break; 76 | 77 | // struct timespec time; 78 | // time.tv_sec = 0; 79 | // time.tv_nsec = rand() % 100000; 80 | // nanosleep(&time , (struct timespec *)NULL); 81 | } 82 | } 83 | 84 | return NULL; 85 | } 86 | 87 | mt_channel_t** testarray; 88 | 89 | void mt_channel_test_main() 90 | { 91 | mt_log_debug("testing mt_channel"); 92 | 93 | testarray = CAL(sizeof(mt_channel_t) * kChTestThreads, NULL, NULL); 94 | 95 | pthread_t* threads = CAL(sizeof(pthread_t) * kChTestThreads * 2, NULL, NULL); 96 | 97 | uint32_t threadidx = 0; 98 | 99 | for (int index = 0; index < kChTestThreads; index++) 100 | { 101 | testarray[index] = mt_channel_new(100); 102 | pthread_create(&threads[threadidx++], NULL, send_test, testarray[index]); 103 | pthread_create(&threads[threadidx++], NULL, recv_test, testarray[index]); 104 | } 105 | 106 | for (uint32_t index = 0; index < threadidx; index++) 107 | { 108 | pthread_join(threads[index], NULL); 109 | } 110 | 111 | REL(threads); 112 | 113 | assert(success == 1); 114 | } 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /src/mt_core_test/mt_core_test.c: -------------------------------------------------------------------------------- 1 | #include "mt_channel_test.c" 2 | #include "mt_log.c" 3 | #include "mt_map_test.c" 4 | #include "mt_memory_test.c" 5 | #include "mt_path_test.c" 6 | #include "mt_string_test.c" 7 | #include "mt_vector_test.c" 8 | 9 | int main(int argc, char* argv[]) 10 | { 11 | mt_log_set_level(MT_LOG_DEBUG); 12 | 13 | mt_memory_test_main(); 14 | mt_vector_test_main(); 15 | mt_map_test_main(); 16 | mt_string_test_main(); 17 | mt_channel_test_main(); 18 | mt_path_test_main(); 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /src/mt_core_test/mt_map_test.c: -------------------------------------------------------------------------------- 1 | #ifndef mt_map_test_h 2 | #define mt_map_test_h 3 | 4 | void mt_map_test_main(); 5 | 6 | #endif 7 | 8 | #if __INCLUDE_LEVEL__ == 0 9 | 10 | #include "mt_log.c" 11 | #include "mt_map.c" 12 | 13 | void mt_map_test_main() 14 | { 15 | char* text1 = "Test text 1"; 16 | char* text2 = "Test text 2"; 17 | 18 | char* ttext1 = mt_memory_stack_to_heap(strlen(text1) + 1, NULL, NULL, (char*) text1); 19 | char* ttext2 = mt_memory_stack_to_heap(strlen(text2) + 1, NULL, NULL, (char*) text2); 20 | 21 | /* checking if map is allocated correctly */ 22 | 23 | mt_log_debug("testing mt_map_new"); 24 | 25 | mt_map_t* map1 = mt_map_new(); 26 | 27 | assert(map1 != NULL); 28 | assert(map1->count == 0); 29 | 30 | /* checking if put works correctly */ 31 | 32 | mt_log_debug("testing mt_map_put"); 33 | 34 | mt_map_put(map1, "text1", ttext1); 35 | 36 | char* ctext1 = mt_map_get(map1, "text1"); 37 | 38 | assert(ttext1 == ctext1); 39 | 40 | /* checking if put release working correctly by checking retain counter */ 41 | 42 | mt_log_debug("testing mt_map_put_rel"); 43 | 44 | mt_map_put_rel(map1, "text2", ttext2); 45 | 46 | char* ctext2 = mt_map_get(map1, "text2"); 47 | 48 | assert(ttext2 == ctext2); 49 | assert(mt_memory_retaincount(ttext2) == 1); 50 | 51 | /* checking if map_keys working correctly */ 52 | 53 | mt_log_debug("testing mt_map_keys"); 54 | 55 | mt_vector_t* keys = mt_vector_new(); 56 | 57 | mt_map_keys(map1, keys); 58 | 59 | assert(keys->length == 2); 60 | 61 | for (size_t index = 0; index < keys->length; index++) 62 | { 63 | char* key = keys->data[index]; 64 | 65 | assert(strcmp(key, "text1") == 0 || strcmp(key, "text2") == 0); 66 | } 67 | 68 | REL(keys); 69 | 70 | /* checking if map_values working correctly */ 71 | 72 | mt_log_debug("testing mt_map_values"); 73 | 74 | mt_vector_t* vals = mt_vector_new(); 75 | 76 | mt_map_values(map1, vals); 77 | 78 | assert(vals->length == 2); 79 | 80 | for (size_t index = 0; index < vals->length; index++) 81 | { 82 | char* val = vals->data[index]; 83 | 84 | assert(val == ttext1 || val == ttext2); 85 | } 86 | 87 | REL(vals); 88 | 89 | /* checking if map_del working correctly */ 90 | 91 | mt_log_debug("testing mt_map_del"); 92 | 93 | mt_map_del(map1, "text2"); 94 | 95 | assert(map1->count == 1); 96 | assert(mt_map_get(map1, "text2") == NULL); 97 | 98 | /* checking if map_reset working correctly */ 99 | 100 | mt_log_debug("testing mt_map_reset"); 101 | 102 | mt_map_reset(map1); 103 | 104 | assert(map1->count == 0); 105 | 106 | /* cleanup, run with leak sanitizer on to check for hidden leaks */ 107 | 108 | REL(ttext1); 109 | REL(map1); 110 | } 111 | 112 | #endif 113 | -------------------------------------------------------------------------------- /src/mt_core_test/mt_memory_test.c: -------------------------------------------------------------------------------- 1 | #ifndef mt_memory_test_h 2 | #define mt_memory_test_h 3 | 4 | void mt_memory_test_main(); 5 | 6 | #endif 7 | 8 | #if __INCLUDE_LEVEL__ == 0 9 | 10 | #include "mt_log.c" 11 | #include "mt_memory.c" 12 | #include 13 | 14 | void test_alloc() 15 | { 16 | mt_log_debug("testing mt_memory_alloc"); 17 | 18 | char* atext = NULL; 19 | 20 | atext = mt_memory_alloc(sizeof(char) * 80, NULL, NULL); 21 | 22 | assert(atext != NULL); 23 | assert(mt_memory_retaincount(atext) == 1); 24 | 25 | mt_memory_release(atext); 26 | } 27 | 28 | void test_calloc() 29 | { 30 | mt_log_debug("testing mt_memory_calloc"); 31 | 32 | char* ctext = NULL; 33 | 34 | ctext = mt_memory_calloc(sizeof(char) * 80, NULL, NULL); 35 | 36 | assert(ctext != NULL); 37 | assert(mt_memory_retaincount(ctext) == 1); 38 | 39 | mt_memory_release(ctext); 40 | } 41 | 42 | void test_stack_to_heap() 43 | { 44 | mt_log_debug("testing mt_memory_stack_to_heap"); 45 | 46 | char* text = "This is a test string"; 47 | char* ttext = mt_memory_stack_to_heap(strlen(text) + 1, NULL, NULL, (char*) text); 48 | 49 | assert(ttext != NULL); 50 | assert(mt_memory_retaincount(ttext) == 1); 51 | assert(strcmp(ttext, text) == 0); 52 | 53 | mt_memory_release(ttext); 54 | } 55 | 56 | void test_realloc() 57 | { 58 | mt_log_debug("testing mt_memory_realloc"); 59 | 60 | char* text0 = "This is a test string"; 61 | char* text1 = "Another text string"; 62 | char* ttext = mt_memory_calloc(strlen(text0) + 1, NULL, NULL); 63 | memcpy(ttext, text0, strlen(text0)); 64 | 65 | ttext = mt_memory_realloc(ttext, strlen(text0) + strlen(text1) + 1); 66 | memcpy(ttext + strlen(text0), text1, strlen(text1)); 67 | 68 | assert(ttext != NULL); 69 | assert(mt_memory_retaincount(ttext) == 1); 70 | assert(strstr(ttext, text0) != NULL); 71 | assert(strstr(ttext, text1) != NULL); 72 | 73 | mt_memory_release(ttext); 74 | } 75 | 76 | int destruct_count = 1; 77 | 78 | void destruct() 79 | { 80 | destruct_count -= 1; 81 | } 82 | 83 | void test_destructor() 84 | { 85 | mt_log_debug("testing mt_memory descructor"); 86 | 87 | char* atext = NULL; 88 | 89 | atext = mt_memory_alloc(sizeof(char) * 80, destruct, NULL); 90 | 91 | assert(atext != NULL); 92 | assert(mt_memory_retaincount(atext) == 1); 93 | 94 | mt_memory_release(atext); 95 | 96 | assert(destruct_count == 0); 97 | } 98 | 99 | int describe_count = 1; 100 | 101 | void describe() 102 | { 103 | describe_count -= 1; 104 | } 105 | 106 | void test_descriptor() 107 | { 108 | mt_log_debug("testing mt_memory descriptor"); 109 | 110 | char* atext = NULL; 111 | 112 | atext = mt_memory_alloc(sizeof(char) * 80, NULL, describe); 113 | 114 | assert(atext != NULL); 115 | assert(mt_memory_retaincount(atext) == 1); 116 | 117 | mt_memory_describe(atext, 0); 118 | mt_memory_release(atext); 119 | 120 | assert(describe_count == 0); 121 | } 122 | 123 | /* run test with clang leak sanitizer */ 124 | 125 | void mt_memory_test_main() 126 | { 127 | test_alloc(); 128 | test_calloc(); 129 | test_stack_to_heap(); 130 | test_realloc(); 131 | test_destructor(); 132 | test_descriptor(); 133 | } 134 | 135 | #endif 136 | -------------------------------------------------------------------------------- /src/mt_core_test/mt_path_test.c: -------------------------------------------------------------------------------- 1 | #ifndef mt_path_test_h 2 | #define mt_path_test_h 3 | 4 | void mt_path_test_main(); 5 | 6 | #endif 7 | 8 | #if __INCLUDE_LEVEL__ == 0 9 | 10 | #include "mt_log.c" 11 | #include "mt_path.c" 12 | #include 13 | #include 14 | 15 | void mt_path_test_main() 16 | { 17 | /* checking if mt_path_new_format works */ 18 | 19 | mt_log_debug("testing mt_path_new_append"); 20 | 21 | char* path1 = mt_path_new_append("root", "exec/"); 22 | 23 | assert(strcmp(path1, "root/exec/") == 0); 24 | 25 | /* checking if mt_path_new_remove_last_component works */ 26 | 27 | mt_log_debug("testing mt_path_new_remove_last_component"); 28 | 29 | char* path2 = mt_path_new_remove_last_component("/home/milgra/whatever.ext"); 30 | 31 | assert(strcmp(path2, "/home/milgra/") == 0); 32 | 33 | /* checking if mt_path_new_extension works */ 34 | 35 | mt_log_debug("testing mt_path_new_extension"); 36 | 37 | char* path3 = mt_path_new_extension("/home/milgra/whatever.ext"); 38 | 39 | assert(strcmp(path3, "ext") == 0); 40 | 41 | /* checking if mt_path_new_filename works */ 42 | 43 | mt_log_debug("testing mt_path_new_filename"); 44 | 45 | char* path4 = mt_path_new_filename("/home/milgra/whatever.ext"); 46 | 47 | assert(strcmp(path4, "whatever") == 0); 48 | 49 | /* checking if mt_path_new_normalize works */ 50 | 51 | mt_log_debug("testing mt_path_new_normalize"); 52 | 53 | char* path5 = mt_path_new_normalize("//milcsi/../whatever.ext"); 54 | 55 | assert(strcmp(path5, "//whatever.ext")); 56 | 57 | REL(path1); 58 | REL(path2); 59 | REL(path3); 60 | REL(path4); 61 | REL(path5); 62 | } 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /src/mt_core_test/mt_string_test.c: -------------------------------------------------------------------------------- 1 | #ifndef mt_string_test_h 2 | #define mt_string_test_h 3 | 4 | void mt_string_test_main(); 5 | 6 | #endif 7 | 8 | #if __INCLUDE_LEVEL__ == 0 9 | 10 | #include "mt_log.c" 11 | #include "mt_string.c" 12 | 13 | void mt_string_test_main() 14 | { 15 | /* char* str = "000 Állítólag svájcban"; */ 16 | 17 | /* checking if mt_string_new_format works */ 18 | 19 | mt_log_debug("testing mt_string_new_format"); 20 | 21 | char* str1 = mt_string_new_format(100, "%s-%i-%x", "milcsi", 100, 64); 22 | 23 | assert(strcmp(str1, "milcsi-100-40") == 0); 24 | 25 | /* checking if mt_string_new_cstring works */ 26 | 27 | mt_log_debug("testing mt_string_new_cstring"); 28 | 29 | char* str2 = mt_string_new_cstring("another cstring"); 30 | 31 | assert(strcmp(str2, "another cstring") == 0); 32 | 33 | /* checking if mt_string_new_substring works */ 34 | 35 | mt_log_debug("testing mt_string_new_substring"); 36 | 37 | char* str3 = mt_string_new_substring("another cstring", 3, 6); 38 | 39 | assert(strcmp(str3, "ther c") == 0); 40 | 41 | /* checking if mt_string_reset works */ 42 | 43 | mt_log_debug("testing mt_string_reset"); 44 | 45 | str1 = mt_string_reset(str1); 46 | 47 | assert(strlen(str1) == 0); 48 | 49 | /* checking if mt_string_append works */ 50 | 51 | mt_log_debug("testing mt_string_append"); 52 | 53 | str1 = mt_string_append(str1, "new string"); 54 | str1 = mt_string_append(str1, "|old string"); 55 | 56 | assert(strcmp(str1, "new string|old string") == 0); 57 | 58 | /* checking if mt_string_append works */ 59 | 60 | mt_log_debug("testing mt_string_append_cp"); 61 | 62 | str1 = mt_string_append_cp(str1, 588); 63 | 64 | assert(strcmp(str1, "new string|old stringɌ") == 0); 65 | 66 | /* checking if mt_string_append_sub works */ 67 | 68 | mt_log_debug("testing mt_string_append_sub"); 69 | 70 | str2 = mt_string_append_sub(str2, "WHAT THE", 2, 3); 71 | 72 | assert(strcmp(str2, "another cstringAT ") == 0); 73 | 74 | /* checking if mt_string_delete_utf_codepoints works */ 75 | 76 | mt_log_debug("testing mt_string_delete_utf_codepoints"); 77 | 78 | str1 = mt_string_delete_utf_codepoints(str1, 4, 18); 79 | 80 | assert(strcmp(str1, "new ") == 0); 81 | 82 | /* checking if mt_string_tokenize works */ 83 | 84 | mt_log_debug("testing mt_string_tokenize"); 85 | 86 | mt_vector_t* vec = mt_string_tokenize("ONE TWO THREE", " "); 87 | 88 | assert(vec->length == 3); 89 | assert(strcmp(vec->data[0], "ONE") == 0); 90 | assert(strcmp(vec->data[1], "TWO") == 0); 91 | assert(strcmp(vec->data[2], "THREE") == 0); 92 | 93 | REL(vec); 94 | REL(str1); 95 | REL(str2); 96 | REL(str3); 97 | } 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /src/mt_core_test/mt_vector_test.c: -------------------------------------------------------------------------------- 1 | #ifndef mt_vector_test_h 2 | #define mt_vector_test_h 3 | 4 | void mt_vector_test_main(); 5 | 6 | #endif 7 | 8 | #if __INCLUDE_LEVEL__ == 0 9 | 10 | #include "mt_log.c" 11 | #include "mt_vector.c" 12 | 13 | void mt_vector_test_main() 14 | { 15 | char* text1 = "Test text 1"; 16 | char* text2 = "Test text 2"; 17 | char* text3 = "Test text 3"; 18 | char* text4 = "Test text 4"; 19 | 20 | char* ttext1 = mt_memory_stack_to_heap(strlen(text1) + 1, NULL, NULL, (char*) text1); 21 | char* ttext2 = mt_memory_stack_to_heap(strlen(text2) + 1, NULL, NULL, (char*) text2); 22 | char* ttext3 = mt_memory_stack_to_heap(strlen(text3) + 1, NULL, NULL, (char*) text3); 23 | char* ttext4 = mt_memory_stack_to_heap(strlen(text4) + 1, NULL, NULL, (char*) text4); 24 | 25 | /* checking if vector allocated correctly */ 26 | 27 | mt_log_debug("testing mt_vector_new"); 28 | 29 | mt_vector_t* vec1 = mt_vector_new(); 30 | 31 | assert(vec1 != NULL); 32 | assert(vec1->length == 0); 33 | 34 | /* checking if add works correctly */ 35 | 36 | mt_log_debug("testing mt_vector_add"); 37 | 38 | mt_vector_add(vec1, ttext1); 39 | 40 | assert(vec1->length == 1); 41 | assert(vec1->data[0] == ttext1); 42 | 43 | /* checking if add release works correctly */ 44 | 45 | mt_log_debug("testing mt_vector_add_rel"); 46 | 47 | mt_vector_add_rel(vec1, ttext2); 48 | 49 | assert(vec1->length == 2); 50 | assert(vec1->data[1] == ttext2); 51 | assert(mt_memory_retaincount(ttext2) == 1); 52 | 53 | /* checking if insert works correctly */ 54 | 55 | mt_log_debug("testing mt_vector_insert"); 56 | 57 | mt_vector_ins(vec1, ttext3, 1); 58 | 59 | assert(vec1->length == 3); 60 | assert(vec1->data[1] == ttext3); 61 | 62 | /* checking if insert release works correctly */ 63 | 64 | mt_log_debug("testing mt_vector_insert_rel"); 65 | 66 | mt_vector_ins_rel(vec1, ttext4, 2); 67 | 68 | assert(vec1->length == 4); 69 | assert(vec1->data[2] == ttext4); 70 | assert(mt_memory_retaincount(ttext4) == 1); 71 | 72 | RET(ttext4); 73 | 74 | /* checking if remove data works correctly */ 75 | 76 | mt_log_debug("testing mt_vector_rem"); 77 | 78 | mt_vector_rem(vec1, ttext1); 79 | 80 | assert(vec1->length == 3); 81 | assert(vec1->data[0] == ttext3); 82 | 83 | /* checking if remove index works correctly */ 84 | 85 | mt_log_debug("testing mt_vector_rem_index"); 86 | 87 | mt_vector_rem_index(vec1, 1); 88 | 89 | assert(vec1->length == 2); 90 | assert(vec1->data[1] == ttext2); 91 | 92 | /* checking if remove range works correctly */ 93 | 94 | mt_log_debug("testing mt_vector_rem_range"); 95 | 96 | mt_vector_rem_range(vec1, 0, 1); 97 | 98 | assert(vec1->length == 0); 99 | 100 | /* checking add in vector */ 101 | 102 | mt_vector_t* vec2 = mt_vector_new(); 103 | mt_vector_add(vec2, ttext1); 104 | mt_vector_add(vec2, ttext2); 105 | mt_vector_add(vec2, ttext3); 106 | mt_vector_add(vec2, ttext4); 107 | 108 | mt_log_debug("testing mt_vector_add_in_vector"); 109 | 110 | mt_vector_add_in_vector(vec1, vec2); 111 | 112 | assert(vec1->length == 4); 113 | assert(vec1->data[3] == ttext4); 114 | 115 | /* checking remove in vector */ 116 | 117 | mt_log_debug("testing mt_vector_rem_in_vector"); 118 | 119 | mt_vector_rem_in_vector(vec1, vec2); 120 | 121 | assert(vec1->length == 0); 122 | 123 | /* checking head and tail */ 124 | 125 | mt_vector_add(vec1, ttext1); 126 | mt_vector_add(vec1, ttext2); 127 | mt_vector_add(vec1, ttext3); 128 | mt_vector_add(vec1, ttext4); 129 | 130 | mt_log_debug("testing mt_vector_head"); 131 | 132 | assert(mt_vector_head(vec1) == ttext1); 133 | 134 | mt_log_debug("testing mt_vector_tail"); 135 | 136 | assert(mt_vector_tail(vec1) == ttext4); 137 | 138 | /* checking reverse */ 139 | 140 | mt_log_debug("testing mt_vector_reverse"); 141 | 142 | mt_vector_reverse(vec1); 143 | 144 | assert(vec1->length == 4); 145 | assert(vec1->data[0] == ttext4); 146 | assert(vec1->data[3] == ttext1); 147 | 148 | /* checking sort */ 149 | 150 | mt_log_debug("testing mt_vector_sort"); 151 | 152 | mt_vector_sort(vec1, (int (*)(void*, void*)) strcmp); 153 | 154 | assert(vec1->length == 4); 155 | assert(vec1->data[0] == ttext1); 156 | assert(vec1->data[3] == ttext4); 157 | 158 | /* checking index of */ 159 | 160 | assert(mt_vector_index_of_data(vec1, ttext2) == 1); 161 | 162 | REL(vec1); 163 | REL(vec2); 164 | REL(ttext1); 165 | REL(ttext2); 166 | REL(ttext3); 167 | REL(ttext4); 168 | REL(ttext4); 169 | } 170 | 171 | #endif 172 | -------------------------------------------------------------------------------- /src/mt_math/mt_vector_2d.c: -------------------------------------------------------------------------------- 1 | #ifndef mt_vector_2d_h 2 | #define mt_vector_2d_h 3 | 4 | #include 5 | #include 6 | 7 | typedef struct _v2_t v2_t; 8 | struct _v2_t 9 | { 10 | float x, y; 11 | }; 12 | 13 | v2_t v2_init(float x, float y); 14 | v2_t v2_add(v2_t a, v2_t b); 15 | v2_t v2_sub(v2_t a, v2_t b); 16 | v2_t v2_scale(v2_t vector, float ratio); 17 | v2_t v2_resize(v2_t a, float size); 18 | v2_t v2_rotate(v2_t vector, float newangle); 19 | v2_t v2_rotate_90_left(v2_t vector); 20 | v2_t v2_rotate_90_right(v2_t vector); 21 | 22 | v2_t v2_midpoints(v2_t pointa, v2_t pointb); 23 | float v2_length(v2_t a); 24 | float v2_angle_x(v2_t a); 25 | float v2_circular_angle_between(v2_t a, v2_t b); 26 | char v2_equals(v2_t a, v2_t b); 27 | void v2_describe(v2_t vector); 28 | float v2_longside(v2_t a); 29 | 30 | #endif 31 | 32 | #if __INCLUDE_LEVEL__ == 0 33 | 34 | #ifndef M_PI 35 | #define M_PI 3.14159265358979323846 36 | #endif 37 | 38 | /* creates vector2 */ 39 | 40 | v2_t v2_init(float x, float y) 41 | { 42 | v2_t result; 43 | 44 | result.x = x; 45 | result.y = y; 46 | 47 | return result; 48 | } 49 | 50 | /* adds two vectors */ 51 | 52 | v2_t v2_add(v2_t a, v2_t b) 53 | { 54 | v2_t result; 55 | 56 | result.x = a.x + b.x; 57 | result.y = a.y + b.y; 58 | 59 | return result; 60 | } 61 | 62 | /* substracts b from a */ 63 | 64 | v2_t v2_sub(v2_t a, v2_t b) 65 | { 66 | v2_t result; 67 | 68 | result.x = a.x - b.x; 69 | result.y = a.y - b.y; 70 | 71 | return result; 72 | } 73 | 74 | /* multiplies vector with ratio */ 75 | 76 | v2_t v2_scale(v2_t vector, float ratio) 77 | { 78 | v2_t result; 79 | 80 | result.x = vector.x * ratio; 81 | result.y = vector.y * ratio; 82 | 83 | return result; 84 | } 85 | 86 | /* resizes vector */ 87 | 88 | v2_t v2_resize(v2_t a, float size) 89 | { 90 | float length = sqrtf(a.x * a.x + a.y * a.y); 91 | float ratio = size / length; 92 | a.x *= ratio; 93 | a.y *= ratio; 94 | return a; 95 | } 96 | 97 | /* rotates vector with given radians */ 98 | 99 | v2_t v2_rotate(v2_t vector, float newangle) 100 | { 101 | float angle = v2_angle_x(vector); 102 | float length = v2_length(vector); 103 | angle += newangle; 104 | return v2_init(cos(angle) * length, sin(angle) * length); 105 | } 106 | 107 | /* rotates vector to left with 90 degrees */ 108 | 109 | v2_t v2_rotate_90_left(v2_t vector) 110 | { 111 | return v2_init(-vector.y, vector.x); 112 | } 113 | 114 | /* rotates vector to right with 90 degrees */ 115 | 116 | v2_t v2_rotate_90_right(v2_t vector) 117 | { 118 | return v2_init(vector.y, -vector.x); 119 | } 120 | 121 | /* returns middle point */ 122 | 123 | v2_t v2_midpoints(v2_t pointa, v2_t pointb) 124 | { 125 | v2_t pointc = v2_sub(pointb, pointa); 126 | 127 | pointc = v2_scale(pointc, 0.5); 128 | pointc = v2_add(pointa, pointc); 129 | 130 | return pointc; 131 | } 132 | 133 | /* returns vector length */ 134 | 135 | float v2_length(v2_t a) 136 | { 137 | return sqrtf(a.x * a.x + a.y * a.y); 138 | } 139 | 140 | /* returns vector angel on x axis */ 141 | 142 | float v2_angle_x(v2_t a) 143 | { 144 | return atan2(a.y, a.x); 145 | } 146 | 147 | /* returns angle between two vector as a circular CCW angle where angle 0 is 148 | * vector a */ 149 | 150 | float v2_circular_angle_between(v2_t a, v2_t b) 151 | { 152 | float anglea = v2_angle_x(a); 153 | float angleb = v2_angle_x(b); 154 | 155 | float anglere = angleb - anglea; 156 | if (anglere < 0.0) 157 | anglere += 2 * M_PI; 158 | return anglere; 159 | } 160 | 161 | /* compares two vectors */ 162 | 163 | char v2_equals(v2_t a, v2_t b) 164 | { 165 | return a.x == b.x && a.y == b.y; 166 | } 167 | 168 | /* describes vector */ 169 | 170 | void v2_describe(v2_t vector) 171 | { 172 | printf("%f %f ", vector.x, vector.y); 173 | } 174 | 175 | /* returns longer side projected to x */ 176 | 177 | float v2_longside(v2_t a) 178 | { 179 | float x = fabs(a.x); 180 | float y = fabs(a.y); 181 | return x > y ? x : y; 182 | } 183 | 184 | #endif 185 | -------------------------------------------------------------------------------- /src/mt_math/mt_vector_3d.c: -------------------------------------------------------------------------------- 1 | #ifndef mt_vector_3d_h 2 | #define mt_vector_3d_h 3 | 4 | #include 5 | 6 | typedef struct _v3_t v3_t; 7 | struct _v3_t 8 | { 9 | float x, y, z; 10 | }; 11 | 12 | v3_t v3_init(float x, float y, float z); 13 | v3_t v3_add(v3_t a, v3_t b); 14 | v3_t v3_sub(v3_t a, v3_t b); 15 | v3_t v3_scale(v3_t a, float f); 16 | v3_t v3_cross(v3_t left, v3_t right); 17 | v3_t v3_normalize(v3_t matrix); 18 | 19 | v3_t v3_rotatearoundx(v3_t vector, float the_angle); 20 | v3_t v3_rotatearoundy(v3_t vector, float the_angle); 21 | v3_t v3_rotatearoundz(v3_t vector, float the_angle); 22 | v3_t v3_getxyunitrotation(v3_t vx, v3_t vy); 23 | v3_t v3_intersectwithplane(v3_t linev1, v3_t linev2, v3_t planev, v3_t planen); 24 | 25 | float v3_dot(v3_t a, v3_t b); 26 | float v3_angle(v3_t a, v3_t b); 27 | float v3_length(v3_t a); 28 | void v3_toarray(v3_t* vector, float* result); 29 | float v3_distance(v3_t vectorA, v3_t vectorB); 30 | 31 | #endif 32 | #if __INCLUDE_LEVEL__ == 0 33 | 34 | /* inits vector3 */ 35 | 36 | v3_t v3_init(float x, float y, float z) 37 | { 38 | v3_t result; 39 | 40 | result.x = x; 41 | result.y = y; 42 | result.z = z; 43 | 44 | return result; 45 | } 46 | 47 | /* add two vectors */ 48 | 49 | v3_t v3_add(v3_t a, v3_t b) 50 | { 51 | v3_t result; 52 | 53 | result.x = a.x + b.x; 54 | result.y = a.y + b.y; 55 | result.z = a.z + b.z; 56 | 57 | return result; 58 | } 59 | 60 | /* substracts b from a */ 61 | 62 | v3_t v3_sub(v3_t a, v3_t b) 63 | { 64 | v3_t result; 65 | 66 | result.x = a.x - b.x; 67 | result.y = a.y - b.y; 68 | result.z = a.z - b.z; 69 | 70 | return result; 71 | } 72 | 73 | /* scales vector */ 74 | 75 | v3_t v3_scale(v3_t a, float f) 76 | { 77 | v3_t result; 78 | 79 | result.x = a.x * f; 80 | result.y = a.y * f; 81 | result.z = a.z * f; 82 | 83 | return result; 84 | } 85 | 86 | /* creates cross product of two vectors */ 87 | 88 | v3_t v3_cross(v3_t left, v3_t right) 89 | { 90 | v3_t v; 91 | 92 | v.x = left.y * right.z - left.z * right.y; 93 | v.y = left.z * right.x - left.x * right.z; 94 | v.z = left.x * right.y - left.y * right.x; 95 | 96 | return v; 97 | } 98 | 99 | /* normalizes vector */ 100 | 101 | v3_t v3_normalize(v3_t matrix) 102 | { 103 | float scale; 104 | 105 | scale = 1.0f / sqrtf(matrix.x * matrix.x + matrix.y * matrix.y + matrix.z * matrix.z); 106 | 107 | matrix.x *= scale; 108 | matrix.y *= scale; 109 | matrix.z *= scale; 110 | 111 | return matrix; 112 | } 113 | 114 | /* rotates vector around it x axis */ 115 | 116 | v3_t v3_rotatearoundx(v3_t vector, float the_angle) 117 | { 118 | float epsilon = 0.00001; 119 | if (fabs(vector.y) > epsilon || fabs(vector.z) > epsilon) 120 | { 121 | float angle = atan2(vector.z, vector.y); 122 | float length = sqrtf(vector.y * vector.y + vector.z * vector.z); 123 | 124 | vector.z = sin(angle + the_angle) * length; 125 | vector.y = cos(angle + the_angle) * length; 126 | } 127 | return vector; 128 | } 129 | 130 | /* rotates vector around it y axis */ 131 | 132 | v3_t v3_rotatearoundy(v3_t vector, float the_angle) 133 | { 134 | float epsilon = 0.00001; 135 | if (fabs(vector.x) > epsilon || fabs(vector.z) > epsilon) 136 | { 137 | float angle = atan2(vector.z, vector.x); 138 | float length = sqrtf(vector.x * vector.x + vector.z * vector.z); 139 | 140 | vector.z = sin(angle + the_angle) * length; 141 | vector.x = cos(angle + the_angle) * length; 142 | } 143 | return vector; 144 | } 145 | 146 | /* rotates vector around it z axis */ 147 | 148 | v3_t v3_rotatearoundz(v3_t vector, float the_angle) 149 | { 150 | float epsilon = 0.00001; 151 | if (fabs(vector.y) > epsilon || fabs(vector.x) > epsilon) 152 | { 153 | float angle = atan2(vector.y, vector.x); 154 | float length = sqrtf(vector.x * vector.x + vector.y * vector.y); 155 | 156 | vector.y = sin(angle + the_angle) * length; 157 | vector.x = cos(angle + the_angle) * length; 158 | } 159 | return vector; 160 | } 161 | 162 | /* rotates back plane to origo, returns rotation vector */ 163 | 164 | v3_t v3_getxyunitrotation(v3_t vx, v3_t vy) 165 | { 166 | v3_t rotation; 167 | 168 | float angle; 169 | float epsilon = 0.00001; 170 | 171 | // rotate back final_x to base_x on Z axis 172 | 173 | if (fabs(vx.x) > epsilon || fabs(vx.y) > epsilon) 174 | { 175 | 176 | angle = atan2(vx.y, vx.x); 177 | 178 | rotation.z = angle; 179 | 180 | vx = v3_rotatearoundz(vx, -angle); 181 | vy = v3_rotatearoundz(vy, -angle); 182 | } 183 | else 184 | rotation.z = 0.0; 185 | 186 | // rotate back final_x to base_x on Y axis 187 | 188 | if (fabs(vx.x) > epsilon || fabs(vx.z) > epsilon) 189 | { 190 | 191 | angle = atan2(vx.z, vx.x); 192 | 193 | rotation.y = -angle; 194 | 195 | vx = v3_rotatearoundy(vx, -angle); 196 | vy = v3_rotatearoundy(vy, -angle); 197 | } 198 | else 199 | rotation.y = 0.0; 200 | 201 | // finally rotate back final_y to base_y on X axis 202 | 203 | if (fabs(vy.y) > epsilon || fabs(vy.z) > epsilon) 204 | { 205 | 206 | angle = atan2(vy.z, vy.y); 207 | 208 | rotation.x = angle; 209 | 210 | vx = v3_rotatearoundx(vx, -angle); 211 | vy = v3_rotatearoundx(vy, -angle); 212 | } 213 | else 214 | rotation.x = 0.0; 215 | 216 | return rotation; 217 | } 218 | 219 | /* intersects vector3 with plane */ 220 | 221 | v3_t v3_intersectwithplane(v3_t linev1, v3_t linev2, v3_t planev, v3_t planen) 222 | { 223 | v3_t u, w, scale, result; 224 | float div; 225 | 226 | u = v3_sub(linev2, linev1); 227 | w = v3_sub(planev, linev1); 228 | div = v3_dot(planen, w) / v3_dot(planen, u); 229 | scale = v3_scale(u, div); 230 | result = v3_add(linev1, scale); 231 | 232 | return result; 233 | } 234 | 235 | /* creates dot product of two vectors */ 236 | 237 | float v3_dot(v3_t a, v3_t b) 238 | { 239 | return a.x * b.x + a.y * b.y + a.z * b.z; 240 | } 241 | 242 | /* calculates angle between two vectors */ 243 | 244 | float v3_angle(v3_t a, v3_t b) 245 | { 246 | return acosf(v3_dot(a, b) / (v3_length(a) * v3_length(b))); 247 | } 248 | 249 | /* calculates vector length */ 250 | 251 | float v3_length(v3_t a) 252 | { 253 | return sqrtf(a.x * a.x + a.y * a.y + a.z * a.z); 254 | } 255 | 256 | /* converts vector to array */ 257 | 258 | void v3_toarray(v3_t* vector, float* result) 259 | { 260 | result[0] = vector->x; 261 | result[1] = vector->y; 262 | result[2] = vector->z; 263 | } 264 | 265 | /* calculates distance of two vectors */ 266 | 267 | float v3_distance(v3_t vectorA, v3_t vectorB) 268 | { 269 | float dx, dy, dz; 270 | 271 | dx = vectorB.x - vectorA.x; 272 | dy = vectorB.y - vectorA.y; 273 | dz = vectorB.z - vectorA.z; 274 | 275 | return sqrtf(dx * dx + dy * dy + dz * dz); 276 | } 277 | 278 | #endif 279 | -------------------------------------------------------------------------------- /src/mt_math/mt_vector_4d.c: -------------------------------------------------------------------------------- 1 | #ifndef mt_vector_4d_h 2 | #define mt_vector_4d_h 3 | 4 | #include "mt_vector_3d.c" 5 | 6 | typedef struct _v4_t v4_t; 7 | struct _v4_t 8 | { 9 | float x, y, z, w; 10 | }; 11 | 12 | v4_t v4_init(float x, float y, float z, float w); 13 | v4_t v4_add(v4_t a, v4_t b); 14 | v4_t v4_sub(v4_t a, v4_t b); 15 | v4_t v4_scale(v4_t a, float f); 16 | void v4_describe(v4_t vector); 17 | 18 | #endif 19 | #if __INCLUDE_LEVEL__ == 0 20 | 21 | #include 22 | 23 | /* creates vector */ 24 | 25 | v4_t v4_init(float x, float y, float z, float w) 26 | { 27 | v4_t result; 28 | 29 | result.x = x; 30 | result.y = y; 31 | result.z = z; 32 | result.w = w; 33 | 34 | return result; 35 | } 36 | 37 | /* adds two vectors */ 38 | 39 | v4_t v4_add(v4_t a, v4_t b) 40 | { 41 | v4_t result; 42 | 43 | result.x = a.x + b.x; 44 | result.y = a.y + b.y; 45 | result.z = a.z + b.z; 46 | result.w = a.w + b.w; 47 | 48 | return result; 49 | } 50 | 51 | /* substract b from a */ 52 | 53 | v4_t v4_sub(v4_t a, v4_t b) 54 | { 55 | v4_t result; 56 | 57 | result.x = a.x - b.x; 58 | result.y = a.y - b.y; 59 | result.z = a.z - b.z; 60 | result.w = a.w - b.w; 61 | 62 | return result; 63 | } 64 | 65 | /* scales vector */ 66 | 67 | v4_t v4_scale(v4_t a, float f) 68 | { 69 | v4_t result; 70 | 71 | result.x = a.x * f; 72 | result.y = a.y * f; 73 | result.z = a.z * f; 74 | result.w = a.w * f; 75 | 76 | return result; 77 | } 78 | 79 | /* describes vector4 */ 80 | 81 | void v4_describe(v4_t vector) 82 | { 83 | printf("x : %f y : %f z : %f w : %f", vector.x, vector.y, vector.z, vector.w); 84 | } 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /src/mt_math_test/mt_math_2d_test.c: -------------------------------------------------------------------------------- 1 | #include "mt_log.c" 2 | 3 | int main(int argc, char* argv[]) 4 | { 5 | mt_log_set_level(MT_LOG_DEBUG); 6 | 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /src/sov/draw.c: -------------------------------------------------------------------------------- 1 | #include "gen.c" 2 | #include "ku_bitmap_ext.c" 3 | #include "ku_renderer_soft.c" 4 | #include "ku_text.c" 5 | #include "mt_log.c" 6 | #include "mt_path.c" 7 | #include "mt_string.c" 8 | #include "mt_string_ext.c" 9 | #include "mt_time.c" 10 | #include "tree.c" 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | int main(int argc, char** argv) 20 | { 21 | mt_log_use_colors(isatty(STDERR_FILENO)); 22 | mt_log_level_info(); 23 | mt_time(NULL); 24 | 25 | /* parse options */ 26 | 27 | char* cfg_par = NULL; 28 | char* tree_par = NULL; 29 | char* ws_par = NULL; 30 | char* res_par = NULL; 31 | 32 | int c, option_index = 0; 33 | 34 | static struct option long_options[] = { 35 | {"tree", required_argument, NULL, 't'}, 36 | {"workspace", required_argument, NULL, 'w'}, 37 | {"style", required_argument, NULL, 's'}, 38 | {"result", required_argument, NULL, 'r'}, 39 | }; 40 | 41 | while ((c = getopt_long(argc, argv, "s:t:w:r:", long_options, &option_index)) != -1) 42 | { 43 | switch (c) 44 | { 45 | case 's': cfg_par = mt_string_new_cstring(optarg); break; 46 | case 't': tree_par = mt_string_new_cstring(optarg); break; 47 | case 'w': ws_par = mt_string_new_cstring(optarg); break; 48 | case 'r': res_par = mt_string_new_cstring(optarg); break; 49 | } 50 | } 51 | 52 | /* init config */ 53 | 54 | char* cfg_path = mt_path_new_normalize(cfg_par); 55 | char* css_path = mt_path_new_append(cfg_path, "html/main.css"); // REL 6 56 | char* html_path = mt_path_new_append(cfg_path, "html/main.html"); // REL 7 57 | char* img_path = mt_path_new_append(cfg_path, "img"); // REL 6 58 | 59 | printf("style path : %s\n", cfg_path); 60 | printf("css path : %s\n", css_path); 61 | printf("html path : %s\n", html_path); 62 | printf("image path : %s\n", img_path); 63 | printf("tree path : %s\n", tree_par); 64 | printf("ws path : %s\n", ws_par); 65 | printf("res path : %s\n", res_par); 66 | 67 | /* init text rendering */ 68 | 69 | ku_text_init(); // DESTROY 1 70 | 71 | /* read sway tree */ 72 | 73 | char* tree_json = mt_string_new_file(tree_par); 74 | char* ws_part = mt_string_new_file(ws_par); 75 | char* ws_json = mt_string_new_cstring("{\"items\":"); 76 | ws_json = mt_string_append(ws_json, ws_part); 77 | ws_json = mt_string_append(ws_json, "}"); 78 | 79 | mt_vector_t* workspaces = VNEW(); 80 | 81 | tree_reader_extract(ws_json, tree_json, workspaces); 82 | 83 | REL(tree_json); 84 | REL(ws_part); 85 | REL(ws_json); 86 | 87 | /* extract outputs */ 88 | 89 | gen_init(html_path, css_path, img_path); 90 | 91 | int cols = 5; 92 | int rows = (int) ceilf((float) workspaces->length / cols); 93 | 94 | sway_workspace_t* ws = workspaces->data[0]; 95 | 96 | int width = 0; 97 | int height = 0; 98 | 99 | gen_calc_size( 100 | ws->width / 7, 101 | ws->height / 7, 102 | 1.0, 103 | cols, 104 | rows, 105 | &width, 106 | &height); 107 | 108 | printf("WIDTH %i HEIGHT %i\n", width, height); 109 | 110 | ku_bitmap_t* bitmap = ku_bitmap_new(width, height); 111 | 112 | gen_render( 113 | ws->width / 7, 114 | ws->height / 7, 115 | 1.0, 116 | cols, 117 | rows, 118 | 0, 119 | workspaces, 120 | bitmap); 121 | 122 | bm_write(bitmap, res_par); 123 | 124 | REL(workspaces); 125 | REL(bitmap); 126 | 127 | /* cleanup */ 128 | 129 | REL(ws_par); 130 | REL(res_par); 131 | REL(tree_par); 132 | if (cfg_par) REL(cfg_par); 133 | REL(cfg_path); 134 | REL(css_path); 135 | REL(html_path); 136 | REL(img_path); 137 | 138 | ku_text_destroy(); 139 | 140 | #ifdef MT_MEMORY_DEBUG 141 | mt_memory_stats(); 142 | #endif 143 | } 144 | -------------------------------------------------------------------------------- /src/sov/json.c: -------------------------------------------------------------------------------- 1 | #ifndef json_h 2 | #define json_h 3 | 4 | #include "mt_vector.c" 5 | 6 | void json_parse(char* string, mt_vector_t* result); 7 | 8 | #endif 9 | 10 | #if __INCLUDE_LEVEL__ == 0 11 | 12 | #include "jsmn.c" 13 | #include "mt_memory.c" 14 | #include "mt_string.c" 15 | #include "mt_string_ext.c" 16 | #include 17 | 18 | char* json_build_path(char* string, jsmntok_t* tokens, char* path, int index) 19 | { 20 | // go to the upmost node 21 | if (tokens[index].parent > -1) path = json_build_path(string, tokens, path, tokens[index].parent); 22 | // if token is string or primitive, add to path 23 | if (tokens[index].type == JSMN_STRING || tokens[index].type == JSMN_PRIMITIVE) 24 | { 25 | path = mt_string_append(path, "/"); 26 | path = mt_string_append_sub(path, string, tokens[index].start, tokens[index].end - tokens[index].start); 27 | } 28 | // if token is array, add index counter to path and increase counter 29 | if (tokens[index].type == JSMN_ARRAY) 30 | { 31 | char istr[10] = {0}; 32 | snprintf(istr, 10, "/%i", tokens[index].aind); 33 | path = mt_string_append(path, istr); 34 | } 35 | 36 | return path; 37 | } 38 | 39 | /* parses c string into an map */ 40 | 41 | void json_parse(char* string, mt_vector_t* result) 42 | { 43 | jsmn_parser parser; 44 | 45 | jsmn_init(&parser); 46 | 47 | int tokcount = 128; 48 | jsmntok_t* tokens = CAL(sizeof(jsmntok_t) * tokcount, NULL, NULL); // REL 0 49 | int actcount = 0; 50 | 51 | while (1) 52 | { 53 | actcount = jsmn_parse(&parser, string, strlen(string), tokens, tokcount); 54 | if (actcount != JSMN_ERROR_NOMEM) 55 | { 56 | break; 57 | } 58 | else 59 | { 60 | tokcount *= 2; 61 | tokens = mt_memory_realloc(tokens, sizeof(jsmntok_t) * tokcount); 62 | } 63 | } 64 | 65 | if (actcount > 0) 66 | { 67 | tokens[0].parent = -1; 68 | 69 | for (int index = 1; index < actcount; index++) 70 | { 71 | jsmntok_t cur_tok = tokens[index]; 72 | jsmntok_t par_tok = tokens[cur_tok.parent]; 73 | 74 | // printf("TOKEN index %i type %i par %i cont %s\n", index, cur_tok.type, cur_tok.parent, strndup(string + cur_tok.start, cur_tok.end - cur_tok.start)); 75 | 76 | // initiate path creation and storage when needed 77 | if (cur_tok.type == JSMN_STRING || cur_tok.type == JSMN_PRIMITIVE) 78 | { 79 | if (par_tok.type == JSMN_STRING || par_tok.type == JSMN_ARRAY) 80 | { 81 | char* val = mt_string_new_cstring(""); 82 | char* esc = NULL; 83 | char* key = mt_string_new_cstring(""); 84 | 85 | val = mt_string_append_sub(val, string, cur_tok.start, cur_tok.end - cur_tok.start); 86 | esc = mt_string_unescape(val); 87 | REL(val); 88 | key = json_build_path(string, tokens, key, cur_tok.parent); 89 | 90 | VADDR(result, key); 91 | VADDR(result, esc); 92 | 93 | // printf("%s - %s\n", key, val); 94 | } 95 | } 96 | // increase array counters 97 | if (par_tok.type == JSMN_ARRAY) 98 | { 99 | tokens[cur_tok.parent].aind += 1; 100 | } 101 | } 102 | } 103 | 104 | REL(tokens); 105 | } 106 | 107 | #endif 108 | -------------------------------------------------------------------------------- /src/sov/ku_bitmap_ext.c: -------------------------------------------------------------------------------- 1 | #ifndef bm_util_h 2 | #define bm_util_h 3 | 4 | #include "ku_bitmap.c" 5 | #include 6 | 7 | ku_bitmap_t* bm_new_flip_y(ku_bitmap_t* bm); 8 | void bm_write(ku_bitmap_t* bm, char* path); 9 | 10 | #endif 11 | 12 | #if __INCLUDE_LEVEL__ == 0 13 | 14 | ku_bitmap_t* bm_new_flip_y(ku_bitmap_t* bm) 15 | { 16 | ku_bitmap_t* tmp = ku_bitmap_new(bm->w, bm->h); 17 | for (int y = 0; y < bm->h; y++) 18 | { 19 | int src_y = bm->h - y - 1; 20 | memcpy(tmp->data + y * bm->w * 4, bm->data + src_y * bm->w * 4, bm->w * 4); 21 | } 22 | return tmp; 23 | } 24 | 25 | void bm_write(ku_bitmap_t* bm, char* path) 26 | { 27 | int w = bm->w; 28 | int h = bm->h; 29 | 30 | FILE* f; 31 | unsigned char* img = NULL; 32 | int filesize = 54 + 3 * w * h; // w is your image width, h is image height, both int 33 | 34 | img = (unsigned char*) malloc(3 * w * h); 35 | memset(img, 0, 3 * w * h); 36 | 37 | for (int i = 0; i < w; i++) 38 | { 39 | for (int j = 0; j < h; j++) 40 | { 41 | int index = j * w * 4 + i * 4; 42 | 43 | int x = i; 44 | int y = j; 45 | 46 | int r = bm->data[index]; 47 | int g = bm->data[index + 1]; 48 | int b = bm->data[index + 2]; 49 | 50 | if (r > 255) r = 255; 51 | if (g > 255) g = 255; 52 | if (b > 255) b = 255; 53 | 54 | img[(x + y * w) * 3 + 2] = (unsigned char) (r); 55 | img[(x + y * w) * 3 + 1] = (unsigned char) (g); 56 | img[(x + y * w) * 3 + 0] = (unsigned char) (b); 57 | } 58 | } 59 | 60 | unsigned char bmpfileheader[14] = {'B', 'M', 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0}; 61 | unsigned char bmpinfoheader[40] = {40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 24, 0}; 62 | unsigned char bmppad[3] = {0, 0, 0}; 63 | 64 | bmpfileheader[2] = (unsigned char) (filesize); 65 | bmpfileheader[3] = (unsigned char) (filesize >> 8); 66 | bmpfileheader[4] = (unsigned char) (filesize >> 16); 67 | bmpfileheader[5] = (unsigned char) (filesize >> 24); 68 | 69 | bmpinfoheader[4] = (unsigned char) (w); 70 | bmpinfoheader[5] = (unsigned char) (w >> 8); 71 | bmpinfoheader[6] = (unsigned char) (w >> 16); 72 | bmpinfoheader[7] = (unsigned char) (w >> 24); 73 | bmpinfoheader[8] = (unsigned char) (h); 74 | bmpinfoheader[9] = (unsigned char) (h >> 8); 75 | bmpinfoheader[10] = (unsigned char) (h >> 16); 76 | bmpinfoheader[11] = (unsigned char) (h >> 24); 77 | 78 | f = fopen(path, "wb"); 79 | fwrite(bmpfileheader, 1, 14, f); 80 | fwrite(bmpinfoheader, 1, 40, f); 81 | for (int i = 0; i < h; i++) 82 | { 83 | fwrite(img + (w * (h - i - 1) * 3), 3, w, f); 84 | fwrite(bmppad, 1, (4 - (w * 3) % 4) % 4, f); 85 | } 86 | 87 | free(img); 88 | fclose(f); 89 | } 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /tst/a_workspace.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 4, 4 | "type": "workspace", 5 | "orientation": "horizontal", 6 | "percent": null, 7 | "urgent": false, 8 | "marks": [], 9 | "layout": "splith", 10 | "border": "none", 11 | "current_border_width": 0, 12 | "rect": { 13 | "x": 5, 14 | "y": 29, 15 | "width": 1910, 16 | "height": 1046 17 | }, 18 | "deco_rect": { 19 | "x": 0, 20 | "y": 0, 21 | "width": 0, 22 | "height": 0 23 | }, 24 | "window_rect": { 25 | "x": 0, 26 | "y": 0, 27 | "width": 0, 28 | "height": 0 29 | }, 30 | "geometry": { 31 | "x": 0, 32 | "y": 0, 33 | "width": 0, 34 | "height": 0 35 | }, 36 | "name": "1", 37 | "window": null, 38 | "nodes": [], 39 | "floating_nodes": [], 40 | "focus": [ 41 | 62 42 | ], 43 | "fullscreen_mode": 1, 44 | "sticky": false, 45 | "num": 1, 46 | "output": "eDP-1", 47 | "representation": "H[V[foot foot]]", 48 | "focused": true, 49 | "visible": true 50 | }, 51 | { 52 | "id": 6, 53 | "type": "workspace", 54 | "orientation": "horizontal", 55 | "percent": null, 56 | "urgent": false, 57 | "marks": [], 58 | "layout": "splith", 59 | "border": "none", 60 | "current_border_width": 0, 61 | "rect": { 62 | "x": 5, 63 | "y": 29, 64 | "width": 1910, 65 | "height": 1046 66 | }, 67 | "deco_rect": { 68 | "x": 0, 69 | "y": 0, 70 | "width": 0, 71 | "height": 0 72 | }, 73 | "window_rect": { 74 | "x": 0, 75 | "y": 0, 76 | "width": 0, 77 | "height": 0 78 | }, 79 | "geometry": { 80 | "x": 0, 81 | "y": 0, 82 | "width": 0, 83 | "height": 0 84 | }, 85 | "name": "2", 86 | "window": null, 87 | "nodes": [], 88 | "floating_nodes": [], 89 | "focus": [ 90 | 7 91 | ], 92 | "fullscreen_mode": 1, 93 | "sticky": false, 94 | "num": 2, 95 | "output": "eDP-1", 96 | "representation": "H[foot]", 97 | "focused": false, 98 | "visible": false 99 | }, 100 | { 101 | "id": 64, 102 | "type": "workspace", 103 | "orientation": "horizontal", 104 | "percent": null, 105 | "urgent": false, 106 | "marks": [], 107 | "layout": "splith", 108 | "border": "none", 109 | "current_border_width": 0, 110 | "rect": { 111 | "x": 5, 112 | "y": 29, 113 | "width": 1910, 114 | "height": 1046 115 | }, 116 | "deco_rect": { 117 | "x": 0, 118 | "y": 0, 119 | "width": 0, 120 | "height": 0 121 | }, 122 | "window_rect": { 123 | "x": 0, 124 | "y": 0, 125 | "width": 0, 126 | "height": 0 127 | }, 128 | "geometry": { 129 | "x": 0, 130 | "y": 0, 131 | "width": 0, 132 | "height": 0 133 | }, 134 | "name": "3", 135 | "window": null, 136 | "nodes": [], 137 | "floating_nodes": [], 138 | "focus": [ 139 | 9 140 | ], 141 | "fullscreen_mode": 1, 142 | "sticky": false, 143 | "num": 3, 144 | "output": "eDP-1", 145 | "representation": "H[google-chrome]", 146 | "focused": false, 147 | "visible": false 148 | }, 149 | { 150 | "id": 12, 151 | "type": "workspace", 152 | "orientation": "horizontal", 153 | "percent": null, 154 | "urgent": false, 155 | "marks": [], 156 | "layout": "splith", 157 | "border": "none", 158 | "current_border_width": 0, 159 | "rect": { 160 | "x": 5, 161 | "y": 29, 162 | "width": 1910, 163 | "height": 1046 164 | }, 165 | "deco_rect": { 166 | "x": 0, 167 | "y": 0, 168 | "width": 0, 169 | "height": 0 170 | }, 171 | "window_rect": { 172 | "x": 0, 173 | "y": 0, 174 | "width": 0, 175 | "height": 0 176 | }, 177 | "geometry": { 178 | "x": 0, 179 | "y": 0, 180 | "width": 0, 181 | "height": 0 182 | }, 183 | "name": "4", 184 | "window": null, 185 | "nodes": [], 186 | "floating_nodes": [], 187 | "focus": [ 188 | 10, 189 | 11 190 | ], 191 | "fullscreen_mode": 1, 192 | "sticky": false, 193 | "num": 4, 194 | "output": "eDP-1", 195 | "representation": "H[google-chrome google-chrome]", 196 | "focused": false, 197 | "visible": false 198 | }, 199 | { 200 | "id": 88, 201 | "type": "workspace", 202 | "orientation": "horizontal", 203 | "percent": null, 204 | "urgent": false, 205 | "marks": [], 206 | "layout": "splith", 207 | "border": "none", 208 | "current_border_width": 0, 209 | "rect": { 210 | "x": 5, 211 | "y": 29, 212 | "width": 1910, 213 | "height": 1046 214 | }, 215 | "deco_rect": { 216 | "x": 0, 217 | "y": 0, 218 | "width": 0, 219 | "height": 0 220 | }, 221 | "window_rect": { 222 | "x": 0, 223 | "y": 0, 224 | "width": 0, 225 | "height": 0 226 | }, 227 | "geometry": { 228 | "x": 0, 229 | "y": 0, 230 | "width": 0, 231 | "height": 0 232 | }, 233 | "name": "5", 234 | "window": null, 235 | "nodes": [], 236 | "floating_nodes": [], 237 | "focus": [ 238 | 89 239 | ], 240 | "fullscreen_mode": 1, 241 | "sticky": false, 242 | "num": 5, 243 | "output": "eDP-1", 244 | "representation": "H[foot]", 245 | "focused": false, 246 | "visible": false 247 | } 248 | ] 249 | -------------------------------------------------------------------------------- /tst/empty_6_workspace.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 7, 4 | "type": "workspace", 5 | "orientation": "horizontal", 6 | "percent": null, 7 | "urgent": false, 8 | "marks": [ 9 | ], 10 | "layout": "splith", 11 | "border": "none", 12 | "current_border_width": 0, 13 | "rect": { 14 | "x": 5, 15 | "y": 29, 16 | "width": 1014, 17 | "height": 734 18 | }, 19 | "deco_rect": { 20 | "x": 0, 21 | "y": 0, 22 | "width": 0, 23 | "height": 0 24 | }, 25 | "window_rect": { 26 | "x": 0, 27 | "y": 0, 28 | "width": 0, 29 | "height": 0 30 | }, 31 | "geometry": { 32 | "x": 0, 33 | "y": 0, 34 | "width": 0, 35 | "height": 0 36 | }, 37 | "name": "6", 38 | "window": null, 39 | "nodes": [ 40 | ], 41 | "floating_nodes": [ 42 | ], 43 | "focus": [ 44 | ], 45 | "fullscreen_mode": 1, 46 | "sticky": false, 47 | "num": 6, 48 | "output": "Virtual-1", 49 | "representation": null, 50 | "focused": true, 51 | "visible": true 52 | } 53 | ] 54 | -------------------------------------------------------------------------------- /tst/empty_tree.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1, 3 | "type": "root", 4 | "orientation": "horizontal", 5 | "percent": null, 6 | "urgent": false, 7 | "marks": [], 8 | "focused": false, 9 | "layout": "splith", 10 | "border": "none", 11 | "current_border_width": 0, 12 | "rect": { 13 | "x": 0, 14 | "y": 0, 15 | "width": 1920, 16 | "height": 1080 17 | }, 18 | "deco_rect": { 19 | "x": 0, 20 | "y": 0, 21 | "width": 0, 22 | "height": 0 23 | }, 24 | "window_rect": { 25 | "x": 0, 26 | "y": 0, 27 | "width": 0, 28 | "height": 0 29 | }, 30 | "geometry": { 31 | "x": 0, 32 | "y": 0, 33 | "width": 0, 34 | "height": 0 35 | }, 36 | "name": "root", 37 | "window": null, 38 | "nodes": [ 39 | { 40 | "id": 2147483647, 41 | "type": "output", 42 | "orientation": "horizontal", 43 | "percent": null, 44 | "urgent": false, 45 | "marks": [], 46 | "focused": false, 47 | "layout": "output", 48 | "border": "none", 49 | "current_border_width": 0, 50 | "rect": { 51 | "x": 0, 52 | "y": 0, 53 | "width": 1920, 54 | "height": 1080 55 | }, 56 | "deco_rect": { 57 | "x": 0, 58 | "y": 0, 59 | "width": 0, 60 | "height": 0 61 | }, 62 | "window_rect": { 63 | "x": 0, 64 | "y": 0, 65 | "width": 0, 66 | "height": 0 67 | }, 68 | "geometry": { 69 | "x": 0, 70 | "y": 0, 71 | "width": 0, 72 | "height": 0 73 | }, 74 | "name": "__i3", 75 | "window": null, 76 | "nodes": [ 77 | { 78 | "id": 2147483646, 79 | "type": "workspace", 80 | "orientation": "horizontal", 81 | "percent": null, 82 | "urgent": false, 83 | "marks": [], 84 | "focused": false, 85 | "layout": "splith", 86 | "border": "none", 87 | "current_border_width": 0, 88 | "rect": { 89 | "x": 0, 90 | "y": 0, 91 | "width": 1920, 92 | "height": 1080 93 | }, 94 | "deco_rect": { 95 | "x": 0, 96 | "y": 0, 97 | "width": 0, 98 | "height": 0 99 | }, 100 | "window_rect": { 101 | "x": 0, 102 | "y": 0, 103 | "width": 0, 104 | "height": 0 105 | }, 106 | "geometry": { 107 | "x": 0, 108 | "y": 0, 109 | "width": 0, 110 | "height": 0 111 | }, 112 | "name": "__i3_scratch", 113 | "window": null, 114 | "nodes": [], 115 | "floating_nodes": [], 116 | "focus": [], 117 | "fullscreen_mode": 1, 118 | "sticky": false 119 | } 120 | ], 121 | "floating_nodes": [], 122 | "focus": [ 123 | 2147483646 124 | ], 125 | "fullscreen_mode": 0, 126 | "sticky": false 127 | }, 128 | { 129 | "id": 3, 130 | "type": "output", 131 | "orientation": "none", 132 | "percent": 1, 133 | "urgent": false, 134 | "marks": [], 135 | "focused": false, 136 | "layout": "output", 137 | "border": "none", 138 | "current_border_width": 0, 139 | "rect": { 140 | "x": 0, 141 | "y": 0, 142 | "width": 1920, 143 | "height": 1080 144 | }, 145 | "deco_rect": { 146 | "x": 0, 147 | "y": 0, 148 | "width": 0, 149 | "height": 0 150 | }, 151 | "window_rect": { 152 | "x": 0, 153 | "y": 0, 154 | "width": 0, 155 | "height": 0 156 | }, 157 | "geometry": { 158 | "x": 0, 159 | "y": 0, 160 | "width": 0, 161 | "height": 0 162 | }, 163 | "name": "eDP-1", 164 | "window": null, 165 | "nodes": [ 166 | { 167 | "id": 4, 168 | "type": "workspace", 169 | "orientation": "horizontal", 170 | "percent": null, 171 | "urgent": false, 172 | "marks": [], 173 | "focused": true, 174 | "layout": "splith", 175 | "border": "none", 176 | "current_border_width": 0, 177 | "rect": { 178 | "x": 5, 179 | "y": 29, 180 | "width": 1910, 181 | "height": 1046 182 | }, 183 | "deco_rect": { 184 | "x": 0, 185 | "y": 0, 186 | "width": 0, 187 | "height": 0 188 | }, 189 | "window_rect": { 190 | "x": 0, 191 | "y": 0, 192 | "width": 0, 193 | "height": 0 194 | }, 195 | "geometry": { 196 | "x": 0, 197 | "y": 0, 198 | "width": 0, 199 | "height": 0 200 | }, 201 | "name": "1", 202 | "window": null, 203 | "nodes": [], 204 | "floating_nodes": [], 205 | "focus": [], 206 | "fullscreen_mode": 1, 207 | "sticky": false, 208 | "num": 1, 209 | "output": "eDP-1", 210 | "representation": "H[]" 211 | } 212 | ], 213 | "floating_nodes": [], 214 | "focus": [ 215 | 4 216 | ], 217 | "fullscreen_mode": 0, 218 | "sticky": false, 219 | "active": true, 220 | "dpms": true, 221 | "primary": false, 222 | "make": "Unknown", 223 | "model": "0x0700", 224 | "serial": "0x00000000", 225 | "scale": 1, 226 | "scale_filter": "nearest", 227 | "transform": "normal", 228 | "adaptive_sync_status": "disabled", 229 | "current_workspace": "1", 230 | "modes": [ 231 | { 232 | "width": 1920, 233 | "height": 1080, 234 | "refresh": 60027 235 | } 236 | ], 237 | "current_mode": { 238 | "width": 1920, 239 | "height": 1080, 240 | "refresh": 60027 241 | }, 242 | "max_render_time": 0 243 | } 244 | ], 245 | "floating_nodes": [], 246 | "focus": [ 247 | 3 248 | ], 249 | "fullscreen_mode": 0, 250 | "sticky": false 251 | } 252 | -------------------------------------------------------------------------------- /tst/empty_workspace.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 4, 4 | "type": "workspace", 5 | "orientation": "horizontal", 6 | "percent": null, 7 | "urgent": false, 8 | "marks": [], 9 | "layout": "splith", 10 | "border": "none", 11 | "current_border_width": 0, 12 | "rect": { 13 | "x": 5, 14 | "y": 29, 15 | "width": 1910, 16 | "height": 1046 17 | }, 18 | "deco_rect": { 19 | "x": 0, 20 | "y": 0, 21 | "width": 0, 22 | "height": 0 23 | }, 24 | "window_rect": { 25 | "x": 0, 26 | "y": 0, 27 | "width": 0, 28 | "height": 0 29 | }, 30 | "geometry": { 31 | "x": 0, 32 | "y": 0, 33 | "width": 0, 34 | "height": 0 35 | }, 36 | "name": "1", 37 | "window": null, 38 | "nodes": [], 39 | "floating_nodes": [], 40 | "focus": [], 41 | "fullscreen_mode": 1, 42 | "sticky": false, 43 | "num": 1, 44 | "output": "eDP-1", 45 | "representation": "H[]", 46 | "focused": true, 47 | "visible": true 48 | } 49 | ] 50 | -------------------------------------------------------------------------------- /tst/feh_workspace.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 78, 4 | "type": "workspace", 5 | "orientation": "horizontal", 6 | "percent": null, 7 | "urgent": false, 8 | "marks": [], 9 | "layout": "splith", 10 | "border": "none", 11 | "current_border_width": 0, 12 | "rect": { 13 | "x": 5, 14 | "y": 29, 15 | "width": 1910, 16 | "height": 1046 17 | }, 18 | "deco_rect": { 19 | "x": 0, 20 | "y": 0, 21 | "width": 0, 22 | "height": 0 23 | }, 24 | "window_rect": { 25 | "x": 0, 26 | "y": 0, 27 | "width": 0, 28 | "height": 0 29 | }, 30 | "geometry": { 31 | "x": 0, 32 | "y": 0, 33 | "width": 0, 34 | "height": 0 35 | }, 36 | "name": "1", 37 | "window": null, 38 | "nodes": [], 39 | "floating_nodes": [], 40 | "focus": [ 41 | 79 42 | ], 43 | "fullscreen_mode": 1, 44 | "sticky": false, 45 | "num": 1, 46 | "output": "eDP-1", 47 | "representation": "H[foot]", 48 | "focused": false, 49 | "visible": false 50 | }, 51 | { 52 | "id": 88, 53 | "type": "workspace", 54 | "orientation": "horizontal", 55 | "percent": null, 56 | "urgent": false, 57 | "marks": [], 58 | "layout": "splith", 59 | "border": "none", 60 | "current_border_width": 0, 61 | "rect": { 62 | "x": 5, 63 | "y": 29, 64 | "width": 1910, 65 | "height": 1046 66 | }, 67 | "deco_rect": { 68 | "x": 0, 69 | "y": 0, 70 | "width": 0, 71 | "height": 0 72 | }, 73 | "window_rect": { 74 | "x": 0, 75 | "y": 0, 76 | "width": 0, 77 | "height": 0 78 | }, 79 | "geometry": { 80 | "x": 0, 81 | "y": 0, 82 | "width": 0, 83 | "height": 0 84 | }, 85 | "name": "2", 86 | "window": null, 87 | "nodes": [], 88 | "floating_nodes": [ 89 | { 90 | "id": 131, 91 | "type": "floating_con", 92 | "orientation": "none", 93 | "percent": 0.11146927212116965, 94 | "urgent": false, 95 | "marks": [], 96 | "focused": true, 97 | "layout": "none", 98 | "border": "none", 99 | "current_border_width": 2, 100 | "rect": { 101 | "x": 305, 102 | "y": 467, 103 | "width": 1310, 104 | "height": 170 105 | }, 106 | "deco_rect": { 107 | "x": 0, 108 | "y": 0, 109 | "width": 0, 110 | "height": 0 111 | }, 112 | "window_rect": { 113 | "x": 0, 114 | "y": 0, 115 | "width": 1310, 116 | "height": 170 117 | }, 118 | "geometry": { 119 | "x": 0, 120 | "y": 0, 121 | "width": 1310, 122 | "height": 170 123 | }, 124 | "name": "feh [14 of 18] - tst/tst_image_floating_a.bmp", 125 | "window": 4194305, 126 | "nodes": [], 127 | "floating_nodes": [], 128 | "focus": [], 129 | "fullscreen_mode": 0, 130 | "sticky": false, 131 | "pid": 142334, 132 | "app_id": null, 133 | "visible": true, 134 | "max_render_time": 0, 135 | "shell": "xwayland", 136 | "inhibit_idle": false, 137 | "idle_inhibitors": { 138 | "user": "none", 139 | "application": "none" 140 | }, 141 | "window_properties": { 142 | "class": "feh", 143 | "instance": "feh", 144 | "title": "feh [14 of 18] - tst/tst_image_floating_a.bmp", 145 | "transient_for": null 146 | } 147 | } 148 | ], 149 | "focus": [ 150 | 131, 151 | 129, 152 | 124 153 | ], 154 | "fullscreen_mode": 1, 155 | "sticky": false, 156 | "num": 2, 157 | "output": "eDP-1", 158 | "representation": "H[foot foot]", 159 | "focused": true, 160 | "visible": true 161 | }, 162 | { 163 | "id": 70, 164 | "type": "workspace", 165 | "orientation": "horizontal", 166 | "percent": null, 167 | "urgent": false, 168 | "marks": [], 169 | "layout": "splith", 170 | "border": "none", 171 | "current_border_width": 0, 172 | "rect": { 173 | "x": 5, 174 | "y": 29, 175 | "width": 1910, 176 | "height": 1046 177 | }, 178 | "deco_rect": { 179 | "x": 0, 180 | "y": 0, 181 | "width": 0, 182 | "height": 0 183 | }, 184 | "window_rect": { 185 | "x": 0, 186 | "y": 0, 187 | "width": 0, 188 | "height": 0 189 | }, 190 | "geometry": { 191 | "x": 0, 192 | "y": 0, 193 | "width": 0, 194 | "height": 0 195 | }, 196 | "name": "3", 197 | "window": null, 198 | "nodes": [], 199 | "floating_nodes": [], 200 | "focus": [ 201 | 72 202 | ], 203 | "fullscreen_mode": 1, 204 | "sticky": false, 205 | "num": 3, 206 | "output": "eDP-1", 207 | "representation": "H[google-chrome]", 208 | "focused": false, 209 | "visible": false 210 | }, 211 | { 212 | "id": 74, 213 | "type": "workspace", 214 | "orientation": "horizontal", 215 | "percent": null, 216 | "urgent": false, 217 | "marks": [], 218 | "layout": "splith", 219 | "border": "none", 220 | "current_border_width": 0, 221 | "rect": { 222 | "x": 5, 223 | "y": 29, 224 | "width": 1910, 225 | "height": 1046 226 | }, 227 | "deco_rect": { 228 | "x": 0, 229 | "y": 0, 230 | "width": 0, 231 | "height": 0 232 | }, 233 | "window_rect": { 234 | "x": 0, 235 | "y": 0, 236 | "width": 0, 237 | "height": 0 238 | }, 239 | "geometry": { 240 | "x": 0, 241 | "y": 0, 242 | "width": 0, 243 | "height": 0 244 | }, 245 | "name": "4", 246 | "window": null, 247 | "nodes": [], 248 | "floating_nodes": [], 249 | "focus": [ 250 | 73 251 | ], 252 | "fullscreen_mode": 1, 253 | "sticky": false, 254 | "num": 4, 255 | "output": "eDP-1", 256 | "representation": "H[google-chrome]", 257 | "focused": false, 258 | "visible": false 259 | } 260 | ] 261 | -------------------------------------------------------------------------------- /tst/floating_workspace.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 4, 4 | "type": "workspace", 5 | "orientation": "horizontal", 6 | "percent": null, 7 | "urgent": false, 8 | "marks": [], 9 | "layout": "splith", 10 | "border": "none", 11 | "current_border_width": 0, 12 | "rect": { 13 | "x": 5, 14 | "y": 29, 15 | "width": 1910, 16 | "height": 1046 17 | }, 18 | "deco_rect": { 19 | "x": 0, 20 | "y": 0, 21 | "width": 0, 22 | "height": 0 23 | }, 24 | "window_rect": { 25 | "x": 0, 26 | "y": 0, 27 | "width": 0, 28 | "height": 0 29 | }, 30 | "geometry": { 31 | "x": 0, 32 | "y": 0, 33 | "width": 0, 34 | "height": 0 35 | }, 36 | "name": "1", 37 | "window": null, 38 | "nodes": [], 39 | "floating_nodes": [ 40 | { 41 | "id": 65, 42 | "type": "floating_con", 43 | "orientation": "none", 44 | "percent": 0.17639073808975606, 45 | "urgent": false, 46 | "marks": [], 47 | "focused": true, 48 | "layout": "none", 49 | "border": "pixel", 50 | "current_border_width": 1, 51 | "rect": { 52 | "x": 609, 53 | "y": 301, 54 | "width": 702, 55 | "height": 502 56 | }, 57 | "deco_rect": { 58 | "x": 0, 59 | "y": 0, 60 | "width": 0, 61 | "height": 0 62 | }, 63 | "window_rect": { 64 | "x": 1, 65 | "y": 1, 66 | "width": 700, 67 | "height": 500 68 | }, 69 | "geometry": { 70 | "x": 0, 71 | "y": 0, 72 | "width": 700, 73 | "height": 500 74 | }, 75 | "name": "mc [milgra@milgra-pc]:~/Downloads", 76 | "window": null, 77 | "nodes": [], 78 | "floating_nodes": [], 79 | "focus": [], 80 | "fullscreen_mode": 0, 81 | "sticky": false, 82 | "pid": 105884, 83 | "app_id": "foot", 84 | "visible": true, 85 | "max_render_time": 0, 86 | "shell": "xdg_shell", 87 | "inhibit_idle": false, 88 | "idle_inhibitors": { 89 | "user": "none", 90 | "application": "none" 91 | } 92 | } 93 | ], 94 | "focus": [ 95 | 65 96 | ], 97 | "fullscreen_mode": 1, 98 | "sticky": false, 99 | "num": 1, 100 | "output": "eDP-1", 101 | "representation": "H[]", 102 | "focused": true, 103 | "visible": true 104 | } 105 | ] 106 | -------------------------------------------------------------------------------- /tst/master/a_result_a.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milgra/sov/19809ae535f8417098020f86ceefa25dbd3c5a90/tst/master/a_result_a.bmp -------------------------------------------------------------------------------- /tst/master/a_result_b.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milgra/sov/19809ae535f8417098020f86ceefa25dbd3c5a90/tst/master/a_result_b.bmp -------------------------------------------------------------------------------- /tst/master/b_result_a.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milgra/sov/19809ae535f8417098020f86ceefa25dbd3c5a90/tst/master/b_result_a.bmp -------------------------------------------------------------------------------- /tst/master/b_result_b.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milgra/sov/19809ae535f8417098020f86ceefa25dbd3c5a90/tst/master/b_result_b.bmp -------------------------------------------------------------------------------- /tst/master/empty_6_result_a.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milgra/sov/19809ae535f8417098020f86ceefa25dbd3c5a90/tst/master/empty_6_result_a.bmp -------------------------------------------------------------------------------- /tst/master/empty_6_result_b.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milgra/sov/19809ae535f8417098020f86ceefa25dbd3c5a90/tst/master/empty_6_result_b.bmp -------------------------------------------------------------------------------- /tst/master/empty_result_a.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milgra/sov/19809ae535f8417098020f86ceefa25dbd3c5a90/tst/master/empty_result_a.bmp -------------------------------------------------------------------------------- /tst/master/empty_result_b.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milgra/sov/19809ae535f8417098020f86ceefa25dbd3c5a90/tst/master/empty_result_b.bmp -------------------------------------------------------------------------------- /tst/master/feh_result_a.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milgra/sov/19809ae535f8417098020f86ceefa25dbd3c5a90/tst/master/feh_result_a.bmp -------------------------------------------------------------------------------- /tst/master/feh_result_b.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milgra/sov/19809ae535f8417098020f86ceefa25dbd3c5a90/tst/master/feh_result_b.bmp -------------------------------------------------------------------------------- /tst/master/floating_result_a.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milgra/sov/19809ae535f8417098020f86ceefa25dbd3c5a90/tst/master/floating_result_a.bmp -------------------------------------------------------------------------------- /tst/master/floating_result_b.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milgra/sov/19809ae535f8417098020f86ceefa25dbd3c5a90/tst/master/floating_result_b.bmp -------------------------------------------------------------------------------- /tst/master/rotated_result_a.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milgra/sov/19809ae535f8417098020f86ceefa25dbd3c5a90/tst/master/rotated_result_a.bmp -------------------------------------------------------------------------------- /tst/master/rotated_result_b.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milgra/sov/19809ae535f8417098020f86ceefa25dbd3c5a90/tst/master/rotated_result_b.bmp -------------------------------------------------------------------------------- /tst/runtests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | exe="$1/draw" 4 | 5 | mkdir -p tst/result 6 | 7 | $exe -s tst/stylea -t tst/a_tree.json -w tst/a_workspace.json -r tst/result/a_result_a.bmp 8 | $exe -s tst/styleb -t tst/a_tree.json -w tst/a_workspace.json -r tst/result/a_result_b.bmp 9 | 10 | $exe -s tst/stylea -t tst/b_tree.json -w tst/b_workspace.json -r tst/result/b_result_a.bmp 11 | $exe -s tst/styleb -t tst/b_tree.json -w tst/b_workspace.json -r tst/result/b_result_b.bmp 12 | 13 | $exe -s tst/stylea -t tst/empty_tree.json -w tst/empty_workspace.json -r tst/result/empty_result_a.bmp 14 | $exe -s tst/styleb -t tst/empty_tree.json -w tst/empty_workspace.json -r tst/result/empty_result_b.bmp 15 | 16 | $exe -s tst/stylea -t tst/empty_6_tree.json -w tst/empty_6_workspace.json -r tst/result/empty_6_result_a.bmp 17 | $exe -s tst/styleb -t tst/empty_6_tree.json -w tst/empty_6_workspace.json -r tst/result/empty_6_result_b.bmp 18 | 19 | $exe -s tst/stylea -t tst/feh_tree.json -w tst/feh_workspace.json -r tst/result/feh_result_a.bmp 20 | $exe -s tst/styleb -t tst/feh_tree.json -w tst/feh_workspace.json -r tst/result/feh_result_b.bmp 21 | 22 | $exe -s tst/stylea -t tst/floating_tree.json -w tst/floating_workspace.json -r tst/result/floating_result_a.bmp 23 | $exe -s tst/styleb -t tst/floating_tree.json -w tst/floating_workspace.json -r tst/result/floating_result_b.bmp 24 | 25 | $exe -s tst/stylea -t tst/rotated_tree.json -w tst/rotated_workspace.json -r tst/result/rotated_result_a.bmp 26 | $exe -s tst/styleb -t tst/rotated_tree.json -w tst/rotated_workspace.json -r tst/result/rotated_result_b.bmp 27 | 28 | diff tst/master tst/result 29 | 30 | error=$? 31 | if [ $error -eq 0 ] 32 | then 33 | echo "No differences found between master and result images" 34 | exit 0 35 | elif [ $error -eq 1 ] 36 | then 37 | echo "Differences found between master and result images" 38 | exit 1 39 | else 40 | echo "Differences found between master and result images" 41 | exit 1 42 | fi 43 | -------------------------------------------------------------------------------- /tst/stylea/html/main.css: -------------------------------------------------------------------------------- 1 | #main { 2 | border-radius: 10px; 3 | background-color: #00000044; 4 | } 5 | 6 | #base { 7 | margin: 15px; 8 | } 9 | 10 | .fullscale { 11 | height: 100%; 12 | width: 100%; 13 | } 14 | 15 | .colflex { 16 | display: flex; 17 | flex-direction: column; 18 | } 19 | 20 | .rowflex { 21 | display: flex; 22 | flex-direction: row; 23 | } 24 | 25 | .workspace { 26 | margin: 10px; 27 | border-radius: 8px; 28 | background-color: #000000FF; 29 | border-width: 1px; 30 | border-color: #555555FF; 31 | } 32 | 33 | .window { 34 | width: 100px; 35 | height: 80px; 36 | background-color: #222222FF; 37 | border-radius: 8px; 38 | border-width: 1px; 39 | border-color: #BCBCBCFF; 40 | } 41 | 42 | .window_active { 43 | width: 100px; 44 | height: 80px; 45 | background-color: #444444FF; 46 | border-radius: 8px; 47 | border-width: 1px; 48 | border-color: #BCBCBCFF; 49 | } 50 | 51 | .title { 52 | width: 100%; 53 | height: 21px; 54 | margin-top: 4px; 55 | margin-left: 4px; 56 | color: #FFFFFFFF; 57 | font-size: 14px; 58 | font-family: "Liberation Mono:style=Bold"; 59 | } 60 | 61 | .content { 62 | width: 100%; 63 | height: 100%; 64 | margin-left: 4px; 65 | color: #999999FF; 66 | vertical-align: top; 67 | font-size: 12px; 68 | font-family: "Liberation Mono:style=Bold"; 69 | word-wrap: break-word; 70 | line-height: 12px; 71 | } 72 | 73 | .number { 74 | width: 20px; 75 | height: 20px; 76 | right: -14px; 77 | top: -9px; 78 | color: #FFFFFFFF; 79 | font-size: 18px; 80 | font-family: "Liberation Mono:style=Bold"; 81 | } 82 | -------------------------------------------------------------------------------- /tst/stylea/html/main.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | 16 | -------------------------------------------------------------------------------- /tst/styleb/html/main.css: -------------------------------------------------------------------------------- 1 | #main { 2 | border-radius: 5px; 3 | background-color: #55006688; 4 | } 5 | 6 | #base { 7 | margin: 10px; 8 | } 9 | 10 | .fullscale { 11 | height: 100%; 12 | width: 100%; 13 | } 14 | 15 | .colflex { 16 | display: flex; 17 | flex-direction: column; 18 | } 19 | 20 | .rowflex { 21 | display: flex; 22 | flex-direction: row; 23 | } 24 | 25 | .workspace { 26 | margin: 5px; 27 | background-color: #000000FF; 28 | border-width: 1px; 29 | border-color: #555555FF; 30 | } 31 | 32 | .window { 33 | width: 100px; 34 | height: 80px; 35 | background-color: #222255BB; 36 | border-width: 1px; 37 | border-color: #BCBCBCFF; 38 | } 39 | 40 | .window_active { 41 | width: 100px; 42 | height: 80px; 43 | background-color: #444444FF; 44 | border-width: 1px; 45 | border-color: #BCBCBCFF; 46 | } 47 | 48 | .title { 49 | width: 100%; 50 | height: 25px; 51 | margin-top: 4px; 52 | margin-left: 4px; 53 | color: #FFFFFFFF; 54 | font-size: 14px; 55 | font-family: "Liberation Serif:style=Italic"; 56 | } 57 | 58 | .content { 59 | width: 100%; 60 | height: 100%; 61 | margin-left: 4px; 62 | color: #999999FF; 63 | vertical-align: top; 64 | font-size: 12px; 65 | font-family: "Liberation Serif:style=Italic"; 66 | word-wrap: break-word; 67 | line-height: 12px; 68 | } 69 | 70 | .number { 71 | width: 20px; 72 | height: 20px; 73 | right: -14px; 74 | top: -9px; 75 | color: #FFFFFFFF; 76 | font-size: 18px; 77 | font-family: "Liberation Serif:style=Italic"; 78 | } 79 | -------------------------------------------------------------------------------- /tst/styleb/html/main.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | 16 | --------------------------------------------------------------------------------