Add wire (node) drawing to schema mode
authorLukáš Jiřiště <gymnazium.jiriste@gmail.com>
Sat, 21 Dec 2024 22:06:45 +0000 (23:06 +0100)
committerLukáš Jiřiště <gymnazium.jiriste@gmail.com>
Sat, 21 Dec 2024 22:17:17 +0000 (23:17 +0100)
Using the "c" key while in schema mode will start the drawing.
When it is started over an existing node, the node is extended, else new
node is created.
When ending on a node, the drawn node and the end node are merged
together.
To exit the mode use any other key than the movement keys (best use
"c"?).

To choose the correct symbol for a segment, the t_node_segment had to be
changed, and with that some functions (unrelated to wire drawing) had to
be changed also.

inc/FET_sim.h
src/build_helper.c
src/colors.c
src/schema_mode.c

index a8c0a84164b17da2b81bd96772fe4092861408a3..12eb9829d4d303b675d0c9855eb4956bc05760a7 100644 (file)
@@ -52,10 +52,18 @@ typedef struct s_position
        long    y;
 }                      t_position;
 
+typedef char t_bitflag;
+
+// connects is a bitflag that encodes which sides the segment is connected to
+// it seems reasonable to use (1 << orientation)
+// UP = 1
+// LEFT = 2
+// DOWN = 4
+// RIGHT = 8
 typedef struct s_node_segment
 {
        t_position      position;
-       t_symbol        symbol;
+       t_bitflag       connects;
 }                              t_node_segment;
 
 typedef struct s_node
@@ -136,6 +144,7 @@ typedef struct s_windows
 }                      t_windows;
 
 t_node         *add_node(t_vec *nodes, t_state set_state);
+void           remove_node(t_vec *nodes, t_node *to_remove);
 t_mosfet       *add_mosfet(t_vec *mosfets, t_type type, t_position pos, t_orientation orient);
 t_node         *get_node_by_id(t_vec *nodes, t_id id);
 t_mosfet       *get_mosfet_by_id(t_vec *mosfets, t_id id);
@@ -152,6 +161,7 @@ const char  *state_color_escape(t_state state);
 void           draw_single(WINDOW *command_win, t_vec *nodes, const t_mosfet *mosfet);
 void           schema_draw_mosfet(WINDOW *schematics_win, t_vec *nodes, const t_mosfet *mosfet);
 void           schema_draw_node(WINDOW *schematics_win, const t_node *node);
+void           schema_draw_segment(WINDOW *schematics_win, const t_node_segment *segment);
 
 void           update_nodes(t_vec *nodes, t_vec *mosfets);
 int                    should_open(t_vec *nodes, const t_mosfet *mosfet);
index ff0f6d90e2ce9430eb091ec896092f4d472c78d1..b8557cac71e52c7bda16ac429855f73be2f91275 100644 (file)
@@ -23,7 +23,7 @@ t_mosfet      *get_connected(t_vec *mosfets, t_vec *connected, size_t ind)
 }
 
 int    node_identity(const void *, const void *);
-static void    remove_node(t_vec *nodes, t_node *to_remove)
+void   remove_node(t_vec *nodes, t_node *to_remove)
 {
        size_t  index;
 
index 0f6cadac1b3367789aca057aaab4a489ec058fc3..525c0db180bde31351e4e9b9c37597c5a4242864 100644 (file)
@@ -130,32 +130,50 @@ void      schema_draw_mosfet(WINDOW *schematics_win, t_vec *nodes, const t_mosfet *mo
        return ;
 }
 
-t_symbol       seg_symbol_to_print(t_symbol seg_symbol)
+t_symbol       seg_connects_to_symbol(t_bitflag connects)
 {
-       if (seg_symbol == 'd' || seg_symbol == 'u')
-               return (ACS_VLINE);
-       else if (seg_symbol == 'r' || seg_symbol == 'l')
-               return (ACS_HLINE);
-       else
-               return (seg_symbol);
+       switch (connects)
+       {
+               case 0x1:       return ('^');
+               case 0x2:       return ('<');
+               case 0x4:       return ('v');
+               case 0x8:       return ('>');
+               case 0x3:       return (ACS_LRCORNER);
+               case 0x6:       return (ACS_URCORNER);
+               case 0xC:       return (ACS_ULCORNER);
+               case 0x9:       return (ACS_LLCORNER);
+               case 0x5:       return (ACS_VLINE);
+               case 0xA:       return (ACS_HLINE);
+               case 0x7:       return (ACS_RTEE);
+               case 0xE:       return (ACS_TTEE);
+               case 0xD:       return (ACS_LTEE);
+               case 0xB:       return (ACS_BTEE);
+               case 0xF:       return (ACS_PLUS);
+               default:        return ('\0');
+       }
+}
+
+void   schema_draw_segment(WINDOW *schematics_win, const t_node_segment *segment)
+{
+       t_symbol                                symbol;
+
+       symbol = seg_connects_to_symbol(segment->connects);
+       if (symbol != '\0')
+               mvwaddch(schematics_win, segment->position.y, segment->position.x, symbol);
+       return ;
 }
 
 void   schema_draw_node(WINDOW *schematics_win, const t_node *node)
 {
        const t_node_segment    *seg;
        size_t                                  i;
-       t_symbol                                symbol;
 
        wattron(schematics_win, COLOR_PAIR(get_state_color(node->state)));
        i = 0;
        while (i < node->segments.size)
        {
                seg = ft_vec_caccess(&node->segments, i);
-               symbol = seg_symbol_to_print(seg->symbol);
-               if (symbol != ' ')
-               {
-                       mvwaddch(schematics_win, seg->position.y, seg->position.x, symbol);
-               }
+               schema_draw_segment(schematics_win, seg);
                ++i;
        }
        wattroff(schematics_win, COLOR_PAIR(get_state_color(node->state)));
index 61534144cfef70ed2694351f22c7c7cf905c63b5..f910b521ac5e86915ffbd0e9ea68fa77732ad02f 100644 (file)
@@ -54,6 +54,11 @@ static t_position    pos_sub(t_position pos1, t_position pos2)
        return (res);
 }
 
+static int     pos_is_equal(t_position pos1, t_position pos2)
+{
+       return ((pos1.x == pos2.x) && (pos1.y == pos2.y));
+}
+
 void   add_terminal_segment(t_node *node, t_mosfet *mosfet, t_terminal term)
 {
        t_node_segment  segment;
@@ -62,38 +67,17 @@ void        add_terminal_segment(t_node *node, t_mosfet *mosfet, t_terminal term)
        if (term == source)
        {
                segment.position = pos_add(mosfet_channel_rel_pos(mosfet), mosfet_up_rel_pos(mosfet));
-               if (mosfet->orientation == LEFT)
-                       segment.symbol = 'd';
-               else if (mosfet->orientation == DOWN)
-                       segment.symbol = 'r';
-               else if (mosfet->orientation == RIGHT)
-                       segment.symbol = 'u';
-               else if (mosfet->orientation == UP)
-                       segment.symbol = 'l';
+               segment.connects = 1 << ((mosfet->orientation + 1) % 4);
        }
        else if (term == drain)
        {
                segment.position = pos_sub(mosfet_channel_rel_pos(mosfet), mosfet_up_rel_pos(mosfet));
-               if (mosfet->orientation == LEFT)
-                       segment.symbol = 'u';
-               else if (mosfet->orientation == DOWN)
-                       segment.symbol = 'l';
-               else if (mosfet->orientation == RIGHT)
-                       segment.symbol = 'd';
-               else if (mosfet->orientation == UP)
-                       segment.symbol = 'r';
+               segment.connects = 1 << ((mosfet->orientation + 3) % 4);
        }
        else if (term == gate)
        {
                segment.position = pos_sub(segment.position, mosfet_channel_rel_pos(mosfet));
-               if (mosfet->orientation == LEFT)
-                       segment.symbol = 'r';
-               else if (mosfet->orientation == DOWN)
-                       segment.symbol = 'u';
-               else if (mosfet->orientation == RIGHT)
-                       segment.symbol = 'l';
-               else if (mosfet->orientation == UP)
-                       segment.symbol = 'd';
+               segment.connects = 1 << ((mosfet->orientation + 2) % 4);
        }
        segment.position = pos_add(segment.position, mosfet->position);
        ft_vec_append(&node->segments, &segment);
@@ -166,6 +150,143 @@ void      schema_add_mosfet(WINDOW *schematics_win, t_vec *nodes, t_vec *mosfets, t_p
        }
 }
 
+t_node_segment *find_node_seg_at_pos(t_node *node, t_position pos)
+{
+       size_t                  i;
+       t_node_segment  *seg;
+
+       i = 0;
+       while (i < node->segments.size)
+       {
+               seg = ft_vec_access(&node->segments, i);
+               if (pos_is_equal(seg->position, pos))
+                       return (seg);
+               ++i;
+       }
+       return (NULL);
+}
+
+t_node *find_node_at_pos(t_vec *nodes, t_position pos)
+{
+       size_t  i;
+       t_node  *node;
+
+       i = 0;
+       while (i < nodes->size)
+       {
+               node = ft_vec_access(nodes, i);
+               if (find_node_seg_at_pos(node, pos))
+                       return (node);
+               ++i;
+       }
+       return (NULL);
+}
+
+t_bitflag      merge_connect(t_bitflag connects1, t_bitflag connects2)
+{
+       return (connects1 | connects2);
+}
+
+int    place_segment(WINDOW *schematics_win, t_node *node, t_node_segment *prediction)
+{
+       char                    ch;
+       t_node_segment  tmp;
+
+       wmove(schematics_win, prediction->position.y, prediction->position.x);
+       ch = wgetch(schematics_win);
+       tmp = *prediction;
+       if (ch == 'l')
+       {
+               tmp.connects = 1 << LEFT;
+               ++tmp.position.x;
+               prediction->connects = merge_connect(prediction->connects, 1 << RIGHT);
+       }
+       else if (ch == 'k')
+       {
+               tmp.connects = 1 << DOWN;
+               --tmp.position.y;
+               prediction->connects = merge_connect(prediction->connects, 1 << UP);
+       }
+       else if (ch == 'j')
+       {
+               tmp.connects = 1 << UP;
+               ++tmp.position.y;
+               prediction->connects = merge_connect(prediction->connects, 1 << DOWN);
+       }
+       else if (ch == 'h')
+       {
+               tmp.connects = 1 << RIGHT;
+               --tmp.position.x;
+               prediction->connects = merge_connect(prediction->connects, 1 << LEFT);
+       }
+       else
+               return (1);     // The choice not to ungetch is deliberate, because it felt weird sing it
+       ft_vec_append(&node->segments, prediction);
+       schema_draw_segment(schematics_win, prediction);
+       *prediction = tmp;
+       return (0);
+}
+
+int    cmp_seg(const void *v_seg1, const void *v_seg2)
+{
+       const t_node_segment    *seg1;
+       const t_node_segment    *seg2;
+
+       seg1 = v_seg1;
+       seg2 = v_seg2;
+       if (seg1->position.x != seg2->position.x)
+               return ((seg1->position.x > seg2->position.x) - (seg1->position.x < seg2->position.x));
+       if (seg1->position.y != seg2->position.y)
+               return ((seg1->position.y > seg2->position.y) - (seg1->position.x < seg2->position.x));
+       return (0);
+}
+
+void   schema_user_draw_node(WINDOW *schematics_win, t_vec *nodes, t_vec *mosfets, t_position pos)
+{
+       t_node                  *chosen_node;
+       t_node                  *end_node;
+       t_node_segment  seg;
+       t_node_segment  *merge_seg;
+       size_t                  index;
+
+       chosen_node = find_node_at_pos(nodes, pos);
+       if (!chosen_node)
+       {
+               chosen_node = add_node(nodes, floating);
+               seg.position = pos;
+               seg.connects = 0;
+       }
+       else
+       {
+               // I'm finding the seg twice here
+               seg = *find_node_seg_at_pos(chosen_node, pos);
+               ft_vec_find_index(&chosen_node->segments, &seg, &index, cmp_seg);
+               ft_vec_erase(&chosen_node->segments, index, NULL);
+       }
+       while (!place_segment(schematics_win, chosen_node, &seg));
+       if (chosen_node->segments.size == 0)
+       {
+               remove_node(nodes, chosen_node);
+               return ;
+       }
+       end_node = find_node_at_pos(nodes, seg.position);
+       if (end_node)
+       {
+               merge_seg = find_node_seg_at_pos(end_node, seg.position);
+               merge_seg->connects = merge_connect(merge_seg->connects, seg.connects);
+               if (end_node->id != chosen_node->id)
+                       merge_nodes(nodes, mosfets, chosen_node, end_node);
+               schema_draw_segment(schematics_win, merge_seg);
+       }
+       else
+       {
+               ft_vec_append(&chosen_node->segments, &seg);
+               schema_draw_segment(schematics_win, &seg);
+       }
+       wmove(schematics_win, seg.position.y, seg.position.x);
+       return ;
+}
+
 int    handle_key_press(int ch, WINDOW *schematics_win, t_vec *nodes, t_vec *mosfets)
 {
        t_position      pos;
@@ -181,6 +302,8 @@ int handle_key_press(int ch, WINDOW *schematics_win, t_vec *nodes, t_vec *mosfet
                wmove(schematics_win, --pos.y, pos.x);
        else if (ch == 't')
                schema_add_mosfet(schematics_win, nodes, mosfets, pos);
+       else if (ch == 'c')
+               schema_user_draw_node(schematics_win, nodes, mosfets, pos);
        return (0);
 }