batebates/sudoku

View on GitHub
src/view/SquareView.rb

Summary

Maintainability
C
1 day
Test Coverage
#===Représente une case de la grille du sudoku en gtk
class SquareView
    private_class_method :new

    @@size = 52;
    @@selectedSquareView = nil;

    attr_reader :caze;

    def SquareView.init(parent, x, y)
        new(parent, x, y);
    end

    def initialize(parent, x, y)
        @caze = SudokuAPI.API.cazeAt(x, y);
        @caze.add_observer(self);

        @squareDraw = Gtk::DrawingArea.new();

        @squareDraw.signal_connect("draw") { |widget, ctx|
            render(self, widget, ctx, x, y);
        }

        @squareDraw.add_events(Gdk::EventMask::BUTTON_PRESS_MASK);
        @squareDraw.add_events(Gdk::EventMask::ENTER_NOTIFY_MASK);
        @squareDraw.add_events(Gdk::EventMask::LEAVE_NOTIFY_MASK);
        @squareDraw.signal_connect("button_press_event") {|widget, event|
            handleClick(event.button, widget);
        }
        @squareDraw.signal_connect("enter_notify_event") {|widget, event|
            onHover(event, widget);
        }
        @squareDraw.signal_connect("leave_notify_event") {|widget, event|
            onLeave(event, widget);
        }
        @squareDraw.set_size_request(@@size, @@size);

        parent.attach(@squareDraw, x, y, 1, 1);
    end

    def render(squareView, idget, ctx, x, y)

        #White background
        setColor(ctx, @caze.color);
        ctx.rectangle(0, 0, @@size, @@size);
        ctx.fill();

        #Top line
        ctx.move_to(0, 0);
        setLineStyle(ctx, x, y, false);
        ctx.rel_line_to(@@size, 0);
        ctx.stroke();

        #Left line
        ctx.move_to(0, 0);
        setLineStyle(ctx, x, y, true);
        ctx.rel_line_to(0, @@size);
        ctx.stroke();

        #Bottom line
        ctx.move_to(0, @@size);
        setLineStyle(ctx, x, y + 1, false);
        ctx.rel_line_to(@@size, 0);
        ctx.stroke();

        #Right line
        ctx.move_to(@@size, 0);
        setLineStyle(ctx, x + 1, y, true);
        ctx.rel_line_to(0, @@size);
        ctx.stroke();

        #Text
        if(@caze.invisible)
            return;
        end

        if(@caze.value == 0)
            hintEnabled = (@caze.hint || Config.getValue("show_hint"));
            possibilities = SudokuAPI.API.candidateCaze(caze.x, caze.y);
            excludedValues = SudokuAPI.API.getExclude(caze.x, caze.y);

            ctx.set_font_size(12);

            for i in 0...9
                x = (i % 3) - 1;
                y = (i / 3) - 1;

                excluded = excludedValues.include?(i + 1);
                if((possibilities.include?(i + 1) && hintEnabled) || excluded)
                    setColor(ctx, Colors::CL_NUMBER);
                    ctx.select_font_face("Arial", Cairo::FONT_SLANT_NORMAL, Cairo::FONT_WEIGHT_NORMAL);
                    textSize = ctx.text_extents((i + 1).to_s);
                    ctx.move_to((@@size / 2) - (textSize.width / 2) + (x * 12), (@@size / 2) + (textSize.height / 2) + (y * 12));
                    ctx.show_text((i + 1).to_s);

                    if(excluded)
                        setColor(ctx, Colors::CL_NUMBER_LOCKED);
                        ctx.select_font_face("Arial", Cairo::FONT_SLANT_NORMAL, Cairo::FONT_WEIGHT_BOLD);
                        textSize = ctx.text_extents("X");
                        ctx.move_to((@@size / 2) - (textSize.width / 2) + (x * 12), (@@size / 2) + (textSize.height / 2) + (y * 12));
                        ctx.show_text("X");
                    end
                end
            end
        else
            if(!@caze.locked)
                setColor(ctx, Colors::CL_NUMBER);
                ctx.select_font_face("Comic sans MS", Cairo::FONT_SLANT_NORMAL, Cairo::FONT_WEIGHT_BOLD);
            else
                setColor(ctx, Colors::CL_NUMBER_LOCKED);
                ctx.select_font_face("Arial", Cairo::FONT_SLANT_NORMAL, Cairo::FONT_WEIGHT_BOLD);
            end
            ctx.set_font_size(13);
            textSize = ctx.text_extents(displayValue());
            ctx.move_to((@@size / 2) - (textSize.width / 2),  (@@size / 2) + (textSize.height / 2));
            ctx.show_text(displayValue());
        end

        return self;
    end

    def setLineStyle(ctx, x, y, vertical)
        isBigLine = vertical ? (x % 3 == 0) : (y % 3 == 0);
        isExternalLine = vertical ? (x == 0 || x == 9) : (y == 0 || y == 9);
        color = 0.0;
        ctx.set_line_width(isBigLine ? (isExternalLine ? 4 : 2) : 0.5);
        ctx.set_source_rgb(color, color, color);
    end

    def handleClick(button, widget)
        if(@caze.locked)
            return;
        end

        overlay = OverlayManager.overlayPanel();
        choiceGrid = overlay.children[0];

        #Set pos of overlay
        pos = widget.translate_coordinates(widget.parent, 0, 0);

        #Border
        pos[0] += 2;
        pos[1] += 2;

        #Center x
        width = choiceGrid.allocation.width;
        height = choiceGrid.allocation.height;
        center = width / 2;
        pos[0] -= center;
        pos[0] += @@size / 2;

        #Clamp X
        pos[0] = [[0, pos[0]].max(), @@size * 9 - width].min();

        #Clamp Y
        pos[1] = pos[1] > @@size * 4.5 ? pos[1] - height : pos[1] + @@size;

        @@selectedSquareView = self;
        OverlayManager.move(pos[0], pos[1]);
        OverlayManager.show();
    end

    def onHover(event, widget)

        lastColor = @caze.color;
        hoverList = [];

        hoverList += (SudokuAPI.API.row(@caze.y) + SudokuAPI.API.column(@caze.x)) unless !Config.getValue("show_line_highlight");
        hoverList += (SudokuAPI.API.square(@caze.x, @caze.y)) unless !Config.getValue("show_square_highlight");

        hoverList.uniq.each{|value|
            value.lastColor = value.color;
            value.color = (value.x == @caze.x || value.y == @caze.y) && Config.getValue("show_line_highlight") ? Colors::CL_HIGHLIGHT_LINE : Colors::CL_HIGHLIGHT_SQUARE;
        };

        @caze.lastColor = lastColor;
        @caze.color = Colors::CL_HIGHLIGHT;
    end

    def onLeave(event, widget)
        hoverList = [];

        hoverList += (SudokuAPI.API.row(@caze.y) + SudokuAPI.API.column(@caze.x)) unless !Config.getValue("show_line_highlight");
        hoverList += (SudokuAPI.API.square(@caze.x, @caze.y)) unless !Config.getValue("show_square_highlight");

        hoverList.uniq.each{|value|
            value.color = value.lastColor;
        };

        @caze.color = @caze.lastColor;
    end

    def redraw()
        @squareDraw.queue_draw_area(0, 0,  @@size, @@size);
    end

    def displayValue()
        return @caze.value == 0 ? "" : @caze.value.to_s;
    end

    def update(type, value)
        redraw();
    end

    def updateCazeReference()
        @caze = SudokuAPI.API.cazeAt(@caze.x, @caze.y);
        @caze.add_observer(self);
        redraw();
    end

    def SquareView.size()
        @@size;
    end

    def SquareView.selectedSquareView()
        @@selectedSquareView;
    end

    def setColor(ctx, color)
        ctx.set_source_rgb(color.red / 65355.0, color.green / 65355.0, color.blue / 65355.0);
    end
end