It certainly would be simpler if you had a PWM on-chip but if pushbutton monitoring and LED control is all the micro is doing, it's pretty trivial to do it all in firmware.
Both the pushbutton monitoring/debouncing and the LED control require decision-making and I/O on a timed basis, and the time intervals for each are similar: around a few milliseconds. In between these intervals, there is nothing for firmware to do, so it could go to sleep, if timer wake-up was available (it seems that it's not available on this device) or just twiddle its thumbs in a wait loop.
Perhaps someone who is familiar with the PIC family could confirm that there's no way to put the micro to sleep and have the timer wake it up. That's how it seems from the data sheet. If this was possible, it would reduce the quiescent operating current while the LEDs are OFF by a significant amount.
Once the desired time duration has elapsed, it needs to read and process the pushbutton input, and calculate and output the LED control value.
From a quick read of the PIC10F200 data sheet, I see that it has an 8-bit free-running up-counter, which can be read and written, and in timer mode is clocked at FCLK/4 which is 1 MHz. You can use a prescaler, but that prescaler is shared with the watchdog timer, and it's not needed with the timer, so I would avoid using it with the the timer.
This means you have an 8-bit up-counter that will wrap around from 0xFF to 0x00 once every 256 microseconds. If you use a 3-bit counter to count wraparounds, that 3-bit counter will wrap from %111 to %000 once every 2048 microseconds (these figures are all approximate because the internal clock is only accurate to +/- 2%). This gives a scanning and PWM clock rate of about 488 Hz which seems reasonable to me.
So your code would look something like:
1. General setup and initialisation
2. Configure and enable timer0 with no prescaler
3. Is tmr0 < 128? (inspect bit 7) if so, loop to 3.
4. Is tmr0 > 127? (inspect bit 7) if so, loop to 4.
5. increment timer rollover counter mod 8
6. is timer rollover counter now zero? if not, loop to 3
7. another 2 ms tick has elapsed. read pushbutton, process new state
8. calculate LED control state and output it to the I/O pin
9. loop to 3.
The functions called at step 7 and 8 are where all the conditional logic resides. The pushbutton read function needs to read the new state of the pushbutton input and perform software debouncing. When a new press is detected, it needs to cycle the PWM control variable to the next value. You might want to include a feature whereby holding the pushbutton down for, say, one second resets the PWM control to OFF. This function will need various variables to keep track of the last known state of the pushbutton, the time since it changed, etc.
The PWM control function needs to calculate the correct state for the output pin that controls the LEDs. If the PWM control variable is 0, i.e. LED OFF, it should simply force the pin OFF and return. Otherwise it needs to keep track of the current position within the PWM cycle, and decide whether the LED should be ON or OFF based on the PWM control variable and the current position in the PWM cycle. The PWM cycle variable would be unconditionally incremented modulo something. You have a tick frequency of 488 Hz; if you want the PWM cycle to be around 80 Hz for no visible flicker, you can divide the 2 ms tick by six. You can then set your two intermediate intensity levels at any of 17%, 33%, 50%, 67% or 83%. If you want finer resolution and/or less flicker, you can increase the tick frequency. You can also use a technique called DPWM to give a smoother result at percentages further from the extremes. Let me know if you want details on DPWM.
Although I've described the pushbutton scanning and PWM update functions as if they were subroutines, there's no need for them to be; if you put them inline, this means the stack isn't used at all.
In this arrangement, a watchdog is not useful for detecting endless loops, since they can't happen unless the clock or counter fails. It would only be useful for detecting when the device has taken a glitch and jumped off and started executing code in neverland.
If you would like any more details feel free to ask.
Edit: Steve is quite right that there's no need for accuracy in this application. You could just as easily do all your timing using delay loops implemented by decrementing a register and looping until it's zero. This requires a bit of "cycle counting", i.e. using the instruction execution times in the data sheet to calculate how many times to loop, but only for the delay loop. If your delay loop delays for, say, 100 us, then you can use an exact percentage value to control the PWM output. For example, if the PWM percentage is 20%, you would turn the LED ON, call the delay function 20 times, turn the LED off, and all the delay function (100-20) times. That would give a PWM cycle time of 10 ms, i.e. a PWM frequency of 100 Hz. The execution time of the rest of the code will be insignificant by comparison to the time spent in the delay functions, and can be ignored.